package com.weimob.mcloud.wechatwork.customer.facade.impl.customer;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValue;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.weimob.marketing.syswechatworkusermanagement.wechatworkusermanagement.service.user.dto.res.vid.RoleVidMemberResp;
import com.weimob.marketing.syswechatworkusermanagement.wechatworkusermanagement.service.user.dto.res.vid.RoleVidResp;
import com.weimob.mcloud.wechatwork.common.utils.JsonUtil;
import com.weimob.mcloud.wechatwork.core.adapter.enums.WosProductType;
import com.weimob.mcloud.wechatwork.core.adapter.enums.cdp.CDPMarkTypeEnum;
import com.weimob.mcloud.wechatwork.core.adapter.enums.cdp.CDPPageNameEnum;
import com.weimob.mcloud.wechatwork.core.adapter.enums.cdp.CdpMarkMessageEventEnum;
import com.weimob.mcloud.wechatwork.core.adapter.enums.channel.WechatWorkAppType;
import com.weimob.mcloud.wechatwork.core.adapter.enums.uc.UCSourceTypeEnum;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.address.request.DivisionRequest;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.address.response.DivisionResponse;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.bos.request.QueryProductInstanceOfRootVidRequest;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.bos.response.ProductInstanceDTO;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.cdp.request.customer.*;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.cdp.response.customer.*;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.cdp.response.customer.CDPUserLogBO.UserBehaviorDTO;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.channel.base.BaseAuthReqDTO;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.channel.request.ExternalContactSyncDTO;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.channel.request.ExternalRemarkUpdateDTO;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.channel.response.WxResponseBaseDTO;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.crm.request.CustomerAssetCrmAdapterRequest;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.crm.request.CustomerCouponsAdapterRequest;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.crm.request.CustomerInfoCrmAdapterRequest;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.ec.request.BatchMigrationStatusRequest;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.ec.response.BatchMigrationStatusVo;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.onecrm.request.CustomerSearchDTO;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.onecrm.response.CustomerSearchBO;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.onecrm.response.ExternalUserBO;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.page.PageInfoResponse;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.passport.response.PassPortAccountMappingRes;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.spi.balance.CustomerBalanceSPIDTO;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.spi.coupon.CustomerCouponSPIDTO;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.spi.customer.CustomerInfoSPIDTO;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.spi.member.MemberCardPlanSPIDTO;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.spi.member.MemberCardSPIDTO;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.spi.point.CustomerPointSPIDTO;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.uc.request.UCInfoFindDTO;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.uc.response.UCInfoDetailResult;
import com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.uc.response.UCInfoFindBO;
import com.weimob.mcloud.wechatwork.core.adapter.service.*;
import com.weimob.mcloud.wechatwork.core.adapter.service.cdp.CdpTagAdapterService;
import com.weimob.mcloud.wechatwork.core.adapter.service.cdp.CdpUserAdapterService;
import com.weimob.mcloud.wechatwork.core.base.MultiResponse;
import com.weimob.mcloud.wechatwork.core.base.SingleRequest;
import com.weimob.mcloud.wechatwork.core.constant.CustomerCoreConstant;
import com.weimob.mcloud.wechatwork.core.entity.base.Address;
import com.weimob.mcloud.wechatwork.core.entity.base.PrivateSphereRelation;
import com.weimob.mcloud.wechatwork.core.entity.privatesphere.PrivateSphere;
import com.weimob.mcloud.wechatwork.core.entity.relation.CustomerEmployeeRelation;
import com.weimob.mcloud.wechatwork.core.entity.relation.customer.*;
import com.weimob.mcloud.wechatwork.core.entity.relation.employee.Employee;
import com.weimob.mcloud.wechatwork.core.entity.relation.tag.TagDetail;
import com.weimob.mcloud.wechatwork.core.enums.customer.*;
import com.weimob.mcloud.wechatwork.core.enums.employee.EmployeeActiveStatusEnum;
import com.weimob.mcloud.wechatwork.core.enums.employee.EmployeeStatusEnum;
import com.weimob.mcloud.wechatwork.core.enums.privateSphere.PrivateSphereEncryptCorpEnum;
import com.weimob.mcloud.wechatwork.core.service.customer.CustomerProcessService;
import com.weimob.mcloud.wechatwork.core.service.customer.CustomerService;
import com.weimob.mcloud.wechatwork.core.service.customer.CustomerStageRelationService;
import com.weimob.mcloud.wechatwork.core.service.customer.request.QueryCustomerProcessRequest;
import com.weimob.mcloud.wechatwork.core.service.customer.response.QueryCustomerProcessResponse;
import com.weimob.mcloud.wechatwork.core.service.employee.DepartmentService;
import com.weimob.mcloud.wechatwork.core.service.privatesphere.PrivateSphereService;
import com.weimob.mcloud.wechatwork.core.service.statistic.StatisticsService;
import com.weimob.mcloud.wechatwork.customer.constant.ExportConstants;
import com.weimob.mcloud.wechatwork.customer.constant.RedisLockConstant;
import com.weimob.mcloud.wechatwork.customer.convertor.customer.CustomerConvert;
import com.weimob.mcloud.wechatwork.customer.convertor.customer.CustomerRequestBuild;
import com.weimob.mcloud.wechatwork.customer.convertor.customer.ExporterConvert;
import com.weimob.mcloud.wechatwork.customer.convertor.customer.RelationConvert;
import com.weimob.mcloud.wechatwork.customer.convertor.tag.CustomerTagCovert;
import com.weimob.mcloud.wechatwork.customer.domain.*;
import com.weimob.mcloud.wechatwork.customer.domain.artemis.CustomerChangeEventMsg;
import com.weimob.mcloud.wechatwork.customer.domain.artemis.CustomerSearchInitEventMsg;
import com.weimob.mcloud.wechatwork.customer.domain.enums.WechatWorkChannelDescEnum;
import com.weimob.mcloud.wechatwork.customer.domain.enums.WosExporterEnum;
import com.weimob.mcloud.wechatwork.customer.enums.UserPermissionRoleEnum;
import com.weimob.mcloud.wechatwork.customer.externalDependencyProxy.contenttouchradar.RadarProxy;
import com.weimob.mcloud.wechatwork.customer.externalDependencyProxy.usermanagement.EmployeeProxy;
import com.weimob.mcloud.wechatwork.customer.externalDependencyProxy.usermanagement.UserPermissionProxy;
import com.weimob.mcloud.wechatwork.customer.facade.impl.customer.dto.RadarRelatedInfoDTO;
import com.weimob.mcloud.wechatwork.customer.mq.handler.externaluser.AddCorpExternaluserSecondHandler;
import com.weimob.mcloud.wechatwork.customer.mq.model.ChatGroupFacade;
import com.weimob.mcloud.wechatwork.customer.redis.RedisService;
import com.weimob.mcloud.wechatwork.customer.service.CustomerEmployeeTagService;
import com.weimob.mcloud.wechatwork.customer.service.TagBaseService;
import com.weimob.mcloud.wechatwork.customer.service.TagManageService;
import com.weimob.mcloud.wechatwork.customer.service.impl.ArtemisService;
import com.weimob.mcloud.wechatwork.customer.service.impl.GroupServiceImpl;
import com.weimob.mcloud.wechatwork.customer.service.user.base.BaseRequest;
import com.weimob.mcloud.wechatwork.customer.service.user.base.BasicInfo;
import com.weimob.mcloud.wechatwork.customer.service.user.base.PageResponse;
import com.weimob.mcloud.wechatwork.customer.service.user.constant.RedisKeyConstant;
import com.weimob.mcloud.wechatwork.customer.service.user.enums.CouponTypeEnum;
import com.weimob.mcloud.wechatwork.customer.service.user.enums.ShortURLSendSceneEnum;
import com.weimob.mcloud.wechatwork.customer.service.user.exception.BaseErrorCode;
import com.weimob.mcloud.wechatwork.customer.service.user.exception.BizException;
import com.weimob.mcloud.wechatwork.customer.service.user.module.bo.customer.*;
import com.weimob.mcloud.wechatwork.customer.service.user.module.bo.customer.CustomerSearchCallbackBO.CorpWxUserInfoListBean;
import com.weimob.mcloud.wechatwork.customer.service.user.module.bo.customer.openapi.CustomerBaseInfoApi;
import com.weimob.mcloud.wechatwork.customer.service.user.module.bo.group.CustomerChatGroupBO;
import com.weimob.mcloud.wechatwork.customer.service.user.module.bo.process.CustomerDetailProcessBO;
import com.weimob.mcloud.wechatwork.customer.service.user.module.bo.process.CustomerStageBO;
import com.weimob.mcloud.wechatwork.customer.service.user.module.bo.tag.TagBO;
import com.weimob.mcloud.wechatwork.customer.service.user.module.bo.tag.TagGroupBO;
import com.weimob.mcloud.wechatwork.customer.service.user.module.dto.customer.*;
import com.weimob.mcloud.wechatwork.customer.service.user.module.dto.customer.openapi.CustomerQueryApi;
import com.weimob.mcloud.wechatwork.customer.service.user.module.dto.group.CustomerChatGroupDTO;
import com.weimob.mcloud.wechatwork.customer.service.user.module.req.tag.CustomerTagQueryDTO;
import com.weimob.mcloud.wechatwork.customer.service.user.utils.SoaResponseUtil;
import com.weimob.mcloud.wechatwork.customer.third.NewRemoteOutServiceProxy;
import com.weimob.mcloud.wechatwork.customer.third.PicServerProxy;
import com.weimob.mcloud.wechatwork.customer.third.PrivateSphereThird;
import com.weimob.mcloud.wechatwork.customer.third.core.CustomerGroupExportServiceProxy;
import com.weimob.mcloud.wechatwork.customer.third.core.CustomerServiceProxy;
import com.weimob.mcloud.wechatwork.customer.third.customer.CustomerThird;
import com.weimob.mcloud.wechatwork.customer.utils.DateUtils;
import com.weimob.saas.mcloud.wechatwork.content.touch.radar.api.domain.bo.RadarConfigDetailBO;
import com.weimob.soa.common.exception.SoaException;
import com.weimob.soa.common.response.SoaResponse;
import com.weimob.soa.common.utils.SoaUtil;
import com.weimob.wechatwork.wechatworkexporter.ExportService;
import com.weimob.wechatwork.wechatworkexporter.enums.ExportTaskTypeEnum;
import com.weimob.wechatwork.wechatworkexporter.req.ExportTaskSaveDTO;
import com.weimob.wechatwork.wechatworkexporter.vo.ExportTaskSaveVo;
import com.weimob.zipkin.ZipkinContext;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.weimob.mcloud.wechatwork.customer.service.user.enums.BizErrorCodeEnum.NULL_PARAMS;

/**
 * @Author yu liu  2021/10/26 19:13
 * Description
 * Version 1.0.0
 **/
@Slf4j
@Service
public class CustomerFacade {
    // CORE
    @Reference
    private PrivateSphereService privateSphereService;

    @Autowired
    private CustomerServiceProxy customerServiceProxy;

    @Reference
    CustomerService customerService;

    @Autowired
    private EmployeeProxy employeeProxy;

    @Reference
    private DepartmentService departmentService;
    @Reference
    private StatisticsService statisticsService;
    @Reference
    private ExportService exportService;

    // ADAPTER
    @Reference
    private OneCrmAdapterService oneCrmAdapterService;
    @Reference
    private CdpUserAdapterService cdpUserAdapterService;
    @Reference
    private CdpTagAdapterService cdpTagAdapterService;
    @Reference
    private AddressAdapterService addressAdapterService;
    @Reference
    private BosAdapterService bosAdapterService;

    @Autowired
    private ChannelAdapterService channelAdapterService;
    @Reference
    private EcAdapterService ecAdapterService;
    @Reference
    private CRMAdapterService crmAdapterService;
    @Autowired
    private UserPermissionProxy userPermissionProxy;

    @Autowired
    private ChatGroupFacade chatGroupFacade;
    @Autowired
    private GroupServiceImpl groupService;
    @Autowired
    private PicServerProxy picServerProxy;
    @Autowired
    private TagManageService tagManageService;
    @Autowired
    private NewRemoteOutServiceProxy remoteOutServiceProxy;
    @Autowired
    @Qualifier("queryCustomerThreadPool")
    private ThreadPoolTaskExecutor queryCustomerThreadPool;
    @Autowired
    @Qualifier("exportCustomerThreadPool")
    private ThreadPoolTaskExecutor exportCustomerThreadPool;

    @Value("${mall.productid}")
    private String mallProductId;

    @Value("${actionlog.default.orgname:关键词打标签}")
    private String actionlogDefaultOrgName;

    @Autowired
    @Qualifier("customerGroupInitialThreadPool")
    private ThreadPoolTaskExecutor customerGroupInitialThreadPool;

    @Value("${manual.sync.externaluser.default.time:60}")
    private Integer manualSyncDefaultTime;

    @Value("${init.sync.externaluser.default.time:60}")
    private Integer autoSyncDefaultTime;

    @Value("${tag.init.interval:60}")
    private Integer tagInitInterval;

    @ApolloJsonValue("${export.productversion.list:[]}")
    private List<Long> exportProductVersionList;

    @ApolloJsonValue("${ipaas.whiteList.bosIds:[]}")
    private List<Long> ipaasWhiteListBosIds;

    @Autowired
    private RedisService redisService;

    @Autowired
    @Qualifier("statisticThreadPool")
    private ThreadPoolTaskExecutor statisticThreadPool;

    @Autowired
    private CustomerThird customerThird;

    @Autowired
    private PrivateSphereThird privateSphereThird;
    @Resource
    private ArtemisService artemisService;
    @Autowired
    private AddCorpExternaluserSecondHandler addCorpExternaluserSecondHandler;

    @Autowired
    private TagBaseService tagBaseService;

    @Reference
    private CustomerProcessService processService;
    /**
     * 企微助手产品id
     */
    @Value("${aewc.productId:203}")
    private Long aewcProductId;

    @Value("${wid.partition.count:20}")
    private Integer widPartitionCount;

    @Value("${customer.query.byId.partition.count:20}")
    private Integer externalUserIdPartitionCount;

    @Reference
    private CustomerStageRelationService stageRelationService;
    @Resource
    private RadarProxy radarProxy;

    public static String EMPLOYEE_SOURCE_STR = "员工 %s 通过 %s 发送";

    public static String CUSTOMER_SOURCE_STR = "客户 %s 的分享";

    @Autowired
    private CustomerEmployeeTagService customerEmployeeTagService;

    @Autowired
    private CustomerFacadeV2 customerFacadeV2;

    @Autowired
    private CustomerGroupExportServiceProxy customerGroupExportServiceProxy;


    private static final List<CdpMarkMessageEventEnum> redpackageEnumsLists =
            Lists.newArrayList(CdpMarkMessageEventEnum.REDPACKAGE_GROUP_RECEIVE,
                    CdpMarkMessageEventEnum.REDPACKAGE_PERSONAL_RECEIVE,
                    CdpMarkMessageEventEnum.REDPACKAGE_RECEIVE_FAILED);


    /**
     * 是否跳过数据隔离
     *
     * @param externalUserInfoFindDTO dto
     * @return
     */
    private Boolean isJumpDataIsolation(ExternalUserInfoFindDTO externalUserInfoFindDTO) {
        //当传了流程和阶段，则不需要数据隔离
        String processId = externalUserInfoFindDTO.getProcessId();
        String stageId = externalUserInfoFindDTO.getStageId();
        if (StringUtils.isNotEmpty(processId) || StringUtils.isNotEmpty(stageId)) {
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }

    /**
     * 查询外部联系人列表
     *
     * @param externalUserInfoFindDTO
     * @return
     */
    public CustomerPageResponse<ExternalUserListBO> queryExternalUserBaseInfoList(
            ExternalUserInfoFindDTO externalUserInfoFindDTO) {

        if (null == externalUserInfoFindDTO) {
            throw new BizException(NULL_PARAMS.getErrorCode(), NULL_PARAMS.getDesc());
        }

        //默认查询有效状态，坐席限制版本、非根目录授权版本查询查询有效状态
        externalUserInfoFindDTO.setStatus(CustomerStatusEnum.DEFAULT.getCode());

        //1、获取corpId（查询都依赖corpID)
        PrivateSphere privateSphere = privateSphereThird.fetch(externalUserInfoFindDTO.getBasicInfo(), true);


        //2、数据隔离判断
        Boolean jumpDataIsolation = isJumpDataIsolation(externalUserInfoFindDTO);
        if (Boolean.FALSE.equals(jumpDataIsolation)) {
            //2.1 数据隔离参数赋值
            this.handlerAuthorizeVidList(privateSphere, externalUserInfoFindDTO);
        }


        //3.根据条件搜索
        PageResponse<ExternalUserListBO> pageResponse = searchExternalUserList(privateSphere, externalUserInfoFindDTO);
        List<ExternalUserListBO> externalUserListBOS = pageResponse.getResults();

        //补全信息
        CountDownLatch countDownLatch = new CountDownLatch(externalUserListBOS.size());
        for (ExternalUserListBO externalUserListBO : externalUserListBOS) {
            queryCustomerThreadPool.submit(() -> {
                try {
                    //补充客户归属门店信息
                    fillCustomerBelongToStoreInfo(privateSphere, externalUserListBO);
                    //补充当前客户标签信息
                    fillCustomerTagInfo(privateSphere, externalUserListBO);
                    //补全客户员工关系
                    fillCustomerEmployeeRelateInfo(privateSphere, externalUserListBO);
                } catch (Exception e) {
                    log.error("补充当前客户关联员工失败，error:", e);
                } finally {
                    countDownLatch.countDown();
                }

            });
        }


        //补全客户消费信息
        CountDownLatch fillCustomerConsumeCountDownLatch = new CountDownLatch(1);
        queryCustomerThreadPool.submit(() -> {
            try {
                //补全客户消费次数和消费金额
                fillCustomerConsumeInfo(privateSphere, externalUserListBOS);
            } catch (Exception e) {
                log.error("补充消费总次数和消费总金额失败，message:{}", e.getMessage());
            } finally {
                fillCustomerConsumeCountDownLatch.countDown();
            }
        });


        //查询客户阶段信息
        Future<Map<String, List<CustomerStageBO>>> stageFuture = queryCustomerThreadPool.submit(() -> {
            Set<String> customerIdSet = CustomerConvert.toCustomerIds(externalUserListBOS);
            try {
                return queryStageInfoByCustomer(customerIdSet, privateSphere);
            } catch (Exception e) {
                log.error("fullStageInfo,customerIds:{} e", customerIdSet, e);
            }
            return new HashMap<>();
        });


        try {
            boolean await = countDownLatch.await(5, TimeUnit.SECONDS);
            if (Boolean.FALSE.equals(await)) {
                log.error("补全客户详细信息超时");
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("InterruptedException e", e);
        } catch (Exception e) {
            log.error("补全客户详细信息失败,error:", e);
        }


        //客户阶段信息填充
        try {
            Map<String, List<CustomerStageBO>> map = stageFuture.get(2, TimeUnit.SECONDS);
            if (!map.isEmpty()) {
                externalUserListBOS.forEach(item -> item.setStages(map.get(item.getCustomerId())));
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("客户阶段数据填充失败 e", e);
        } catch (Exception e) {
            log.error("客户阶段数据填充失败 e", e);
        }


        try {
            //等待填充客户消费金额和消费次数, 等待3秒
            boolean await = fillCustomerConsumeCountDownLatch.await(3, TimeUnit.SECONDS);
            if (Boolean.FALSE.equals(await)) {
                log.error("补全客户消费次数和消费金额超时");
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("InterruptedException e", e);
        } catch (Exception e) {
            log.error("补全客户消费次数和消费金额, param:{},  error:", externalUserInfoFindDTO, e);
        }


        CustomerPageResponse<ExternalUserListBO> customerPageResponse = new CustomerPageResponse<>();
        customerPageResponse.setResults(externalUserListBOS);
        customerPageResponse.setTotalCount(pageResponse.getTotalCount());
        return customerPageResponse;
    }

    /**
     * 补充客户归属门店信息
     */
    private void fillCustomerBelongToStoreInfo(PrivateSphere privateSphere, ExternalUserListBO externalUserListBO) {
        CDPUserInfoGetDTO cdpUserInfoGetDTO = new CDPUserInfoGetDTO();
        cdpUserInfoGetDTO.setBosId(privateSphere.getBosId());
        cdpUserInfoGetDTO.setWid(externalUserListBO.getExternalUserWid());
        cdpUserInfoGetDTO.setCorpId(privateSphere.getCorpId());

        CDPUserAttributeBO cdpUserAttributeBO = null;
        try {
            SoaResponse<CDPUserAttributeBO, ?> soaResponse = cdpUserAdapterService.getCDPBaseUserInfo(cdpUserInfoGetDTO);
            if (0L != Long.parseLong(soaResponse.getReturnCode())) {
                log.error("查询客户归属门店信息失败, request:{}, response:{}", cdpUserInfoGetDTO, JSON.toJSONString(soaResponse));
                return;
            }

            cdpUserAttributeBO = soaResponse.getResponseVo();
        } catch (Exception e) {
            log.error("查询客户归属门店失败，request:{}, message:{}", JSON.toJSONString(cdpUserInfoGetDTO), e);
            return;
        }


        if (null == cdpUserAttributeBO) {
            return;
        }
        externalUserListBO.setBelongToStoreName(cdpUserAttributeBO.getBelongToStoreName());
    }

    /**
     * 补充客户标签信息
     *
     * @param privateSphere
     * @param externalUserListBO
     */
    private void fillCustomerTagInfo(PrivateSphere privateSphere, ExternalUserListBO externalUserListBO) {

        try {

            CustomerTagQueryDTO customerTagQueryDTO = new CustomerTagQueryDTO();
            customerTagQueryDTO.setBosId(privateSphere.getBosId());
            customerTagQueryDTO.setExternalUserId(externalUserListBO.getExternalUserId());


            List<TagBO> tagBOS = tagManageService.queryCustomerTag(customerTagQueryDTO);
            externalUserListBO.setTagBOList(tagBOS);

        } catch (Exception e) {
            log.error("补充当前客户标签信息失败，message:", e);
        }

    }


    private void fillCustomerEmployeeRelateInfo(PrivateSphere privateSphere, ExternalUserListBO externalUserListBO) {

        //默认流失
        externalUserListBO.setFlowStatus(true);

        MultiResponse<CustomerEmployeeRelation> multiResponse = null;
        try {
            multiResponse = customerServiceProxy.fetchCustomerEmployeeRelationPage(externalUserListBO.getCustomerId(), null, privateSphere, true, CustomerStatusEnum.DEFAULT, null, 1, 999);
        } catch (Exception e) {
            log.warn("客户员工关系查询失败, customerId:{}", externalUserListBO.getCustomerId());
            return;
        }

        if (null == multiResponse || CollectionUtils.isEmpty(multiResponse.getDataList())) {
            log.warn("客户员工关系不存在, customerId:{}", externalUserListBO.getCustomerId());
            return;
        }

        List<CustomerEmployeeRelation> customerEmployeeRelationList = multiResponse.getDataList();

        //根据时间倒序展示 设置最新添加事件添加方式
        List<CustomerEmployeeRelation> sortedDataList = customerEmployeeRelationList.stream().sorted(Comparator.comparing(CustomerEmployeeRelation::getAddTime).reversed()).collect(Collectors.toList());
        CustomerEmployeeRelation relation = sortedDataList.get(0);
        externalUserListBO.setRecentlyAddTime(relation.getAddTime());


        ExternalUserAddWayEnum addWay = relation.getAddWay();
        if (Objects.nonNull(addWay)) {
            externalUserListBO.setAddWay(addWay.getCode());
            externalUserListBO.setAddWayDesc(addWay.getDesc());
        }


        //二级添加方式
        SubAddWayEnum subAddWay = relation.getSubAddWay();
        if (Objects.nonNull(subAddWay)) {
            externalUserListBO.setSubAddWay(subAddWay.getCode());
            externalUserListBO.setSubAddWayDesc(subAddWay.getDesc());
        }


        List<SimpleUserListBO> simpleUserListBOList = Lists.newArrayList();
        for (CustomerEmployeeRelation customerEmployeeRelation : sortedDataList) {

            if (customerEmployeeRelation.getFriended() != null) {
                //默认已流失，发现有好友关系情况存在，代表未流失
                if (customerEmployeeRelation.getFriended()) {
                    externalUserListBO.setFlowStatus(false);
                }
            }


            SimpleUserListBO simpleUserListBO = new SimpleUserListBO();
            simpleUserListBO.setOrgUserId(customerEmployeeRelation.getEmployee().getId());
            simpleUserListBO.setUserName(customerEmployeeRelation.getEmployee().getName());
            if (CollectionUtils.isNotEmpty(customerEmployeeRelation.getEmployee().getGuiderList())) {
                simpleUserListBO.setHaveBindGuide(true);
            }

            simpleUserListBOList.add(simpleUserListBO);
        }
        externalUserListBO.setUserList(simpleUserListBOList);
    }


    /**
     * 补充客户消费信息
     *
     * @param privateSphere
     * @param externalUserListBOS
     */
    private void fillCustomerConsumeInfo(PrivateSphere privateSphere, List<ExternalUserListBO> externalUserListBOS) {

        List<String> widList = CustomerConvert.toWidList(externalUserListBOS);
        List<CDPUserConsumptionBO> cdpUserConsumptionBOList = queryCDPConsumeInfo(privateSphere.getBosId(), widList);
        if (CollectionUtils.isNotEmpty(cdpUserConsumptionBOList)) {

            //key:wid， value:CDPUserConsumptionBO
            Map<String, CDPUserConsumptionBO> cdpUserConsumptionMap = new HashMap<>();
            for (CDPUserConsumptionBO cdpUserConsumptionBO : cdpUserConsumptionBOList) {
                if (cdpUserConsumptionBO.getWid() == null) {
                    continue;
                }
                cdpUserConsumptionMap.put(cdpUserConsumptionBO.getWid(), cdpUserConsumptionBO);
            }


            for (ExternalUserListBO externalUserListBO : externalUserListBOS) {
                CDPUserConsumptionBO cdpUserConsumptionBO = cdpUserConsumptionMap.get(externalUserListBO.getExternalUserWid() + "");
                if (cdpUserConsumptionBO != null) {
                    externalUserListBO.setConsumeTimes(cdpUserConsumptionBO.getTotalConsumptionCount());
                    externalUserListBO.setTotalConsumeAmount(cdpUserConsumptionBO.getTotalConsumeAmount());
                }
            }
        }
    }

    /**
     * 查询客户消费信息
     * 消费金额
     * 消费次数
     *
     * @param bosId
     * @param widList
     * @return
     */
    private List<CDPUserConsumptionBO> queryCDPConsumeInfo(Long bosId, List<String> widList) {
        if (CollectionUtils.isEmpty(widList)) {
            return new ArrayList<>();
        }

        CDPUserConsumptionDTO cdpUserConsumptionDTO = new CDPUserConsumptionDTO();
        cdpUserConsumptionDTO.setBosId(bosId);
        cdpUserConsumptionDTO.setWidList(widList);

        SoaResponse<List<CDPUserConsumptionBO>, ?> soaResponse =
                cdpUserAdapterService.getCDPUserConsumptionList(cdpUserConsumptionDTO);
        if (0L != Long.parseLong(soaResponse.getReturnCode())) {
            log.error("查询cdp客户消费信息失败, request:{}, response:{}", JSON.toJSONString(cdpUserConsumptionDTO), JSON.toJSONString(soaResponse));
            return new ArrayList<>();
        }
        return soaResponse.getResponseVo();
    }

    // 处理数据隔离 返回是否为超级管理员
    public RoleVidInfo handlerAuthorizeVidList(PrivateSphere privateSphere, ExternalUserInfoFindDTO externalUserInfoFindDTO) {
        RoleVidInfo roleVidInfo = new RoleVidInfo();
        // 数据隔离权限判断
        List<Long> authorizeVidList = null;
        String employeeId = null;
        if (Objects.nonNull(externalUserInfoFindDTO.getBwid())) {
            //
            RoleVidResp roleVidResp = userPermissionProxy.getRoleVid(privateSphere, null, externalUserInfoFindDTO.getBwid());
            if (Objects.nonNull(roleVidResp) && Objects.nonNull(roleVidResp.getWidRole())) {
                RoleVidMemberResp widRole = roleVidResp.getWidRole();
                roleVidInfo.setRoleType(widRole.getRoleType());
                // 超级管理员查看所有数据-无需处理
                // 普通管理员查看managerVidList下数据
                if (UserPermissionRoleEnum.MANAGER.getRoleType().equals(widRole.getRoleType())) {
                    authorizeVidList = widRole.getVidList();
                    roleVidInfo.setAuthorizeVidList(widRole.getVidList());
                }
                // 普通员工查看自己为群主的群数据
                if (UserPermissionRoleEnum.EMPLOYEE.getRoleType().equals(widRole.getRoleType())) {
                    employeeId = widRole.getEmployeeId();
                    roleVidInfo.setEmployeeId(employeeId);
                }
            }
        }
        externalUserInfoFindDTO.setAuthorizeVidList(authorizeVidList);
        if (CollectionUtils.isEmpty(externalUserInfoFindDTO.getOrgUserIdList()) && employeeId != null) {
            externalUserInfoFindDTO.setOrgUserIdList(Lists.newArrayList(employeeId));
        }
        return roleVidInfo;
    }

    /**
     * 查询客户所属员工列表
     *
     * @param customerDetailDTO
     * @return
     */
    public PageResponse<ExternalUserRelationBO> getEmployeeByCustomerId(CustomerDetailDTO customerDetailDTO) {
        PageResponse<ExternalUserRelationBO> pageResponse = new PageResponse<>();

        //1、获取corpId
        PrivateSphere privateSphere = privateSphereThird.fetch(customerDetailDTO.getBasicInfo(), true);

        //2、获取客户员工关系
        CustomerIdGetDTO customerIdGetDTO = new CustomerIdGetDTO();
        customerIdGetDTO.setBasicInfo(customerDetailDTO.getBasicInfo());
        customerIdGetDTO.setCustomerId(customerDetailDTO.getCustomerId());
        customerIdGetDTO.setExternalUserId(customerDetailDTO.getExternalUserId());
        CustomerDetailBO customerBaseInfo = this.getCustomerBaseInfo(customerIdGetDTO, privateSphere);
        if (customerBaseInfo == null) {
            return pageResponse;
        }

        // 客户所属员工查在授权范围内的
        if (StringUtils.isBlank(customerBaseInfo.getCustomerId())) {
            return pageResponse;
        }

        MultiResponse<CustomerEmployeeRelation> customerEmployeeRelationPageInfoResponse = null;
        try {
            customerEmployeeRelationPageInfoResponse = customerServiceProxy.fetchCustomerEmployeeRelationPage(customerBaseInfo.getCustomerId(), null, privateSphere, null, CustomerStatusEnum.DEFAULT, customerDetailDTO.getFriended(), customerDetailDTO.getPageNum(), customerDetailDTO.getPageSize());

            pageResponse.setTotalCount(customerEmployeeRelationPageInfoResponse.getTotalCount());
            if (CollectionUtils.isEmpty(customerEmployeeRelationPageInfoResponse.getDataList())) {
                return pageResponse;
            }
        } catch (Exception e) {
            log.error("查询客户关系数据错误,error", e);
            return pageResponse;
        }

        // 3.查员工
        List<String> orgUserIds = Lists.newArrayList();
        for (CustomerEmployeeRelation customerEmpRelResponse : customerEmployeeRelationPageInfoResponse.getDataList()) {
            orgUserIds.add(customerEmpRelResponse.getEmployee().getId());
        }
        MultiResponse<Employee> multiResponse = employeeProxy.getByEmployeeIdOrTxUserIds(privateSphere, orgUserIds, null, true, true);
        if (Objects.isNull(multiResponse) || CollectionUtils.isEmpty(multiResponse.getDataList())) {
            return pageResponse;
        }
        List<Employee> employeeList = multiResponse.getDataList();

        Map<String, Employee> employeeMap = employeeList.stream().collect(Collectors.toMap(PrivateSphereRelation::getId, v -> v, (v1, v2) -> v1));

        //4、查询员工客户标签
        List<TagDetail> tagDetailList = customerEmployeeTagService.fetchCustomerEmployeeTag(privateSphere, customerBaseInfo.getExternalUserId(), null, true);;

        Map<String, List<TagDetail>> orgUserIdAndCustomerTagMap = CustomerTagCovert.toOrgUserIdAndCustomerTagMap(tagDetailList);

        List<ExternalUserRelationBO> externalUserRelationDetailBOs = new CopyOnWriteArrayList<>();
        CountDownLatch countDownLatch = new CountDownLatch(customerEmployeeRelationPageInfoResponse.getDataList().size());
        for (CustomerEmployeeRelation relationItem : customerEmployeeRelationPageInfoResponse.getDataList()) {
            queryCustomerThreadPool.submit(() -> {
                try {
                    ExternalUserRelationBO externalUserRelationBO = new ExternalUserRelationBO();
                    //添加方式
                    ExternalUserAddWayEnum addWay = relationItem.getAddWay();
                    if (Objects.nonNull(addWay)) {
                        externalUserRelationBO.setAddWay(addWay.getCode());
                        externalUserRelationBO.setAddWayDesc(addWay.getDesc());
                    }
                    //二级添加方式
                    SubAddWayEnum subAddWay = relationItem.getSubAddWay();
                    if (Objects.nonNull(subAddWay)) {
                        externalUserRelationBO.setSubAddWay(subAddWay.getCode());
                        externalUserRelationBO.setSubAddWayDesc(subAddWay.getDesc());
                    }
                    externalUserRelationBO.setCustomerId(relationItem.getCustomerId());
                    externalUserRelationBO.setEmployeeId(relationItem.getEmployee().getId());
                    externalUserRelationBO.setAddTime(relationItem.getAddTime());
                    externalUserRelationBO.setState(relationItem.getState());
                    externalUserRelationBO.setFriended(Boolean.TRUE.equals(relationItem.getFriended()) ? 1 : 0);
                    externalUserRelationBO.setLoseTime(relationItem.getLoseTime());
                    externalUserRelationBO.setUserName(relationItem.getEmployee().getName());

                    // 员工部门先取第一个
                    if (employeeMap.get(relationItem.getEmployee().getId()) != null) {
                        Employee employee = employeeMap.get(relationItem.getEmployee().getId());
                        if (CollectionUtils.isNotEmpty(employee.getDepartments())) {
                            externalUserRelationBO.setDepartmentId(employee.getDepartments().get(0).getId());
                            externalUserRelationBO.setDepartmentName(employee.getDepartments().get(0).getName());
                        }
                        if (CollectionUtils.isNotEmpty(employee.getGuiderList())) {
                            externalUserRelationBO.setHaveBindGuide(true);
                        } else {
                            externalUserRelationBO.setHaveBindGuide(false);
                        }
                    }

                    if (MapUtils.isNotEmpty(orgUserIdAndCustomerTagMap)) {
                        Employee employee = employeeMap.get(relationItem.getEmployee().getId());
                        if (Objects.nonNull(employee)) {
                            List<TagDetail> customerTags = orgUserIdAndCustomerTagMap.get(employee.getId());
                            List<TagDetailBO> tagDetailBOS = CustomerTagCovert.toTagDetailBO(customerTags);
                            if (CollectionUtils.isNotEmpty(tagDetailBOS)) {
                                externalUserRelationBO.setTagDetailList(tagDetailBOS);
                            }
                        }
                    }

                    externalUserRelationDetailBOs.add(externalUserRelationBO);
                } catch (Exception e) {
                    log.error("单条客户所属员工数据补充失败，item:{}，e", relationItem, e);
                } finally {
                    countDownLatch.countDown();
                }
            });
        }
        try {
            boolean await = countDownLatch.await(5, TimeUnit.SECONDS);
            if (Boolean.FALSE.equals(await)) {
                log.error("查询客户所属员工列表超时");
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("InterruptedException e", e);
        } catch (Exception e) {
            log.error("查询客户所属员工列表失败，error", e);
        }
        externalUserRelationDetailBOs.sort((e1, e2) -> e2.getAddTime().compareTo(e1.getAddTime()));
        pageResponse.setResults(externalUserRelationDetailBOs);
        return pageResponse;
    }

    /**
     * 根据wids获取企微外部联系人基础信息 结果和wid顺序保持一致
     */
    public List<ExternalUserListBO> getExternalUserInfoByWids(PrivateSphere privateSphere, List<Long> widList, Integer customerStatus, Boolean fetchCustomerDetail) {

        Map<Long, ExternalUserListBO> mapResult = Maps.newLinkedHashMap();

        for (Long wid : widList) {
            mapResult.put(wid, null);
        }

        Long bosId = privateSphere.getBosId();
        String corpId = privateSphere.getCorpId();
        List<PassPortAccountMappingRes> accountMappingList = queryAccountMapping(corpId, bosId, widList);
        if (CollectionUtils.isEmpty(accountMappingList)) {
            return Lists.newArrayList();
        }


        Map<String, Long> externalUserIdWidMap = new HashMap<>();
        for (PassPortAccountMappingRes ucInfoDetailResult : accountMappingList) {
            externalUserIdWidMap.put(ucInfoDetailResult.getExternalUserId(), ucInfoDetailResult.getWid());
        }


        List<String> externalUserIdList = CustomerConvert.toExternalUserIdListFromMapping(accountMappingList);
        if (CollectionUtils.isEmpty(externalUserIdList)) {
            return Lists.newArrayList();
        }


        List<List<String>> externalUserIdPartition = Lists.partition(externalUserIdList, externalUserIdPartitionCount);
        List<Customer> customerList = new ArrayList<>();
        for (List<String> partExternalUserIdList : externalUserIdPartition) {
            //2、根据externaluserid 去企微助手获取customer
            try {
                List<Customer> customerResponses = customerServiceProxy.fetchCustomerByIds(partExternalUserIdList, privateSphere, customerStatus, fetchCustomerDetail);
                if (CollectionUtils.isEmpty(customerResponses)) {
                    continue;
                }
                customerList.addAll(customerResponses);
            } catch (Exception e) {
                log.error("根据externaluserid 去企微助手获取customer失败，message:", e);
            }
        }


        for (Customer customerResponse : customerList) {
            ExternalUserListBO externalUserInfoBO = new ExternalUserListBO();
            externalUserInfoBO.setCorpId(corpId);
            externalUserInfoBO.setCustomerId(customerResponse.getId());
            if (customerResponse.getExternalUserType() != null) {
                externalUserInfoBO.setExternalUserType(customerResponse.getExternalUserType().getCode());
            }
            externalUserInfoBO.setExternalUserWid(externalUserIdWidMap.get(customerResponse.getExternalUserid()));
            externalUserInfoBO.setExternalUserId(customerResponse.getExternalUserid());
            externalUserInfoBO.setUnionid(customerResponse.getUnionid());
            externalUserInfoBO.setPhone(customerResponse.getPhone());
            externalUserInfoBO.setExternalUserName(customerResponse.getName());
            externalUserInfoBO.setGender(customerResponse.getGender().getCode());
            externalUserInfoBO.setAvatar(customerResponse.getAvatar());
            externalUserInfoBO.setFirstAddTime(customerResponse.getFirstAddTime());
            // customer_detail的手机号
            externalUserInfoBO.setMobiles(customerResponse.getMobiles());
            //客户星级
            externalUserInfoBO.setCustomerRating(customerResponse.getCustomerRatingCode());
            WechatworkChannelEnum channel;
            if ((channel = customerResponse.getChannel()) != null) {
                WechatWorkChannelDescEnum enumByValue = WechatWorkChannelDescEnum.getEnumByValue(channel.getCode());
                externalUserInfoBO.setOtherChannel(enumByValue.getDesc());
            }
            if (customerResponse.getStatus() != null) {
                externalUserInfoBO.setStatus(customerResponse.getStatus().getCode());
            }
            mapResult.put(externalUserInfoBO.getExternalUserWid(), externalUserInfoBO);
        }
        return mapResult.values().stream().filter(Objects::nonNull).collect(Collectors.toList());
    }

    /**
     * 查询passport，根据wid换externalUserId
     *
     * @param corpId
     * @param bosId
     * @param widList
     * @return
     */
    private List<PassPortAccountMappingRes> queryAccountMapping(String corpId, Long bosId, List<Long> widList) {
        if (CollectionUtils.isEmpty(widList)) {
            return new ArrayList<>();
        }

        List<List<Long>> widPartition = Lists.partition(widList, widPartitionCount);

        List<PassPortAccountMappingRes> passportAccountMappingRes = new ArrayList<>();
        for (List<Long> partWidList : widPartition) {
            //根据wid查询externalUserId
            List<PassPortAccountMappingRes> passportAccountMapping = remoteOutServiceProxy.getPassportAccountMappingRes(bosId, corpId, partWidList, null);
            if (CollectionUtils.isEmpty(passportAccountMapping)) {
                continue;
            }

            passportAccountMappingRes.addAll(passportAccountMapping);
        }


        return passportAccountMappingRes;
    }

    /**
     * 根据pid+List<wid> 获取外部联系人+成员关系
     */
    public List<ExternalUserRelationBO> getExternalUserRelationByWids(ExternalUserInfoByWidsDTO externalUserInfoByWidsDTO) {
        //0.根据basicInfo，换取私域
        PrivateSphere privateSphere = privateSphereThird.fetch(externalUserInfoByWidsDTO.getBasicInfo(), true);

        checkPrivateSphere(privateSphere);

        List<ExternalUserListBO> externalUserInfoByWids = this.getExternalUserInfoByWids(privateSphere,
                externalUserInfoByWidsDTO.getWids(), externalUserInfoByWidsDTO.getStatus(), false);

        if (CollectionUtils.isEmpty(externalUserInfoByWids)) {
            return new ArrayList<>();
        }
        List<String> customerIds = externalUserInfoByWids.stream().map(item -> item.getCustomerId()).collect(Collectors.toList());

        if (CollectionUtils.isEmpty(customerIds)) {
            return new ArrayList<>();
        }

        Map<String, ExternalUserListBO> customerIdList = externalUserInfoByWids.stream().collect(Collectors.toMap(
                ExternalUserListBO::getCustomerId, Function.identity(), (k1, k2) -> k1));

        String employeeId = "";
        if (externalUserInfoByWidsDTO.getUserId() != null) {
            Employee employee = employeeProxy.fetchEmployeeById(privateSphere, externalUserInfoByWidsDTO.getUserId(), null);
            if (employee != null) {
                employeeId = employee.getId();
            }
        }

        CustomerStatusEnum statusEnum = null;
        if (externalUserInfoByWidsDTO.getStatus() != null) {
            statusEnum = CustomerStatusEnum.getEnumByCode(externalUserInfoByWidsDTO.getStatus());
        }

        List<CustomerEmployeeRelation> dataList = null;
        List<ExternalUserRelationBO> externalUserRelationBOList = new ArrayList<>();
        try {
            dataList = customerServiceProxy.fetchCustomerEmployeeRelation(customerIds, employeeId, privateSphere, statusEnum);
        } catch (Exception e) {
            log.error("查询员工客户关系数据失败,error", e);
            return externalUserRelationBOList;
        }

        if (CollectionUtils.isNotEmpty(dataList)) {
            for (CustomerEmployeeRelation item : dataList) {
                // 特殊情况 wid有问题查不到外部联系人信息
                if (customerIdList.get(item.getCustomerId()) == null) {
                    continue;
                }
                ExternalUserRelationBO externalUserRelationBO = new ExternalUserRelationBO();
                externalUserRelationBO.setCorpId(item.getCorpId());
                externalUserRelationBO.setCustomerId(item.getCustomerId());
                if (item.getEmployee() != null) {
                    externalUserRelationBO.setEmployeeId(item.getEmployee().getId());
                }
                if (item.getAddWay() != null) {
                    externalUserRelationBO.setAddWay(item.getAddWay().getCode());
                }
                externalUserRelationBO.setState(item.getState());
                externalUserRelationBO.setAddTime(item.getAddTime());
                externalUserRelationBO.setFriended(item.getFriended() == true ? 1 : 0);
                externalUserRelationBO.setExternalUserId(customerIdList.get(item.getCustomerId()).getExternalUserId());
                externalUserRelationBO.setWid(customerIdList.get(item.getCustomerId()).getExternalUserWid());
                if (item.getStatus() != null) {
                    externalUserRelationBO.setStatus(item.getStatus().getCode());
                }
                externalUserRelationBOList.add(externalUserRelationBO);
            }
        }

        return externalUserRelationBOList;
    }

    private List<CustomerDetailProcessBO> queryRelationByCustomerId(String customerId, PrivateSphere privateSphere) {
        //1.获取此客户阶段信息
        CustomerStageRelation stageRelation = new CustomerStageRelation();
        stageRelation.setPrivateSphere(privateSphere);
        stageRelation.setCustomer(stageRelation.toCustomer(customerId));

        SingleRequest<CustomerStageRelation> request = new SingleRequest<>(stageRelation);
        Map<String, Object> extInfo = request.getExtInfo();
        extInfo.put(CustomerCoreConstant.FETCH_STAGE, Boolean.TRUE);
        extInfo.put(CustomerCoreConstant.FETCH_EMPLOYEE, Boolean.TRUE);
        extInfo.put(CustomerCoreConstant.FETCH_PROCESS, Boolean.TRUE);
        MultiResponse<CustomerStageRelation> multiResponse = SoaUtil.unpack(stageRelationService.fetchRelationList(request));
        List<CustomerStageRelation> dataList = multiResponse.getDataList();

        List<CustomerDetailProcessBO> result = new ArrayList<>();
        if (CollectionUtils.isEmpty(dataList)) {
            return result;
        }

        //3.查询所有的流程 阶段详情
        QueryCustomerProcessRequest queryCustomerProcessRequest = new QueryCustomerProcessRequest();
        queryCustomerProcessRequest.setPrivateSphere(privateSphere);
        SingleRequest<QueryCustomerProcessRequest> processReq = new SingleRequest<>(queryCustomerProcessRequest);
        QueryCustomerProcessResponse processResponse = SoaUtil.unpack(processService.queryAllIncludeStageBaseInfo(processReq));

        if (Objects.isNull(processResponse) || CollectionUtils.isEmpty(processResponse.getProcessList())) {
            return result;
        }

        //2.结果处理
        Map<String, CustomerStageRelation> stageRelationMap = dataList.stream().collect(Collectors.toMap(CustomerStageRelation::getStageId, i -> i, (t1, t2) -> t1));
        Map<String, CustomerStageRelation> processMap = dataList.stream().collect(Collectors.toMap(CustomerStageRelation::getProcessId, i -> i, (t1, t2) -> t1));

        List<CustomerProcess> processList = processResponse.getProcessList();

        processList.forEach(item -> {
            //当前流程如果没有关联过，则不需要展示
            if (!processMap.containsKey(item.getProcessId())) {
                return;
            }
            //组装
            CustomerDetailProcessBO processBO = new CustomerDetailProcessBO();
            //流程名称
            processBO.setProcessName(item.getProcessName());

            List<CustomerStage> customerStages = item.getCustomerStages();
            if (CollectionUtils.isNotEmpty(customerStages)) {
                List<CustomerDetailProcessBO.CustomerStageInfo> stageInfos = new ArrayList<>();
                for (CustomerStage customerStage : customerStages) {
                    CustomerDetailProcessBO.CustomerStageInfo customerStageInfo = new CustomerDetailProcessBO.CustomerStageInfo();
                    customerStageInfo.setStageName(customerStage.getStageName());
                    CustomerStageRelation relation = stageRelationMap.get(customerStage.getStageId());
                    if (Objects.nonNull(relation)) {
                        customerStageInfo.setCurrentStage(relation.getCurrentStage());
                        customerStageInfo.setRemark(relation.getRemark());
                        customerStageInfo.setFollowEmployee(relation.getEmployee().getName());
                    }
                    stageInfos.add(customerStageInfo);
                }
                processBO.setCustomerStageInfoList(stageInfos);
            }
            result.add(processBO);
        });

        return result;
    }

    /**
     * 查询客户详情
     *
     * @param queryDTO
     * @return
     */
    public CustomerDetailBO queryCustomerDetail(CustomerDetailDTO queryDTO) {

        if (StringUtils.isEmpty(queryDTO.getExternalUserId()) && StringUtils.isEmpty(queryDTO.getCustomerId())) {
            throw new SoaException(BaseErrorCode.PARMA_EXCPETION.getCode().toString(), BaseErrorCode.PARMA_EXCPETION.getMsg());
        }

        //1.根据basicInfo，换取私域
        PrivateSphere privateSphere = privateSphereThird.fetch(queryDTO.getBasicInfo(), true);

        //2、获取客户基本信息
        Customer customer = customerServiceProxy.fetchCustomer(queryDTO.getCustomerId(), queryDTO.getExternalUserId(), privateSphere, ExternalUserTypeEnum.ALL);
        if (customer == null) {
            return null;
        }

        CustomerDetailBO customerDetailBO = new CustomerDetailBO();
        customerDetailBO.setCustomerId(customer.getId());
        customerDetailBO.setExternalUserId(customer.getExternalUserid());
        customerDetailBO.setNickName(customer.getName());
        customerDetailBO.setAvatar(customer.getAvatar());
        customerDetailBO.setGender(customer.getGender().getCode());
        customerDetailBO.setCustomerType(Objects.isNull(customer.getExternalUserType()) ?
                ExternalUserTypeEnum.WECHAT_CUSTOMER.getCode() : customer.getExternalUserType().getCode());
        customerDetailBO.setPosition(customer.getPosition());
        customerDetailBO.setCorpName(customer.getCorpName());
        customerDetailBO.setCorpFullName(customer.getCorpFullName());
        customerDetailBO.setQq(customer.getQq());
        customerDetailBO.setBirthday(customer.getBirthday());
        customerDetailBO.setPhone(customer.getPhone());
        if (StringUtils.isEmpty(customer.getMobiles()) && StringUtils.isNotEmpty(customer.getPhone())) {
            customerDetailBO.setMobiles(customer.getPhone());
        } else {
            customerDetailBO.setMobiles(customer.getMobiles());
        }

        if (customer.getAddress() != null) {
            customerDetailBO.setAddress(customer.getAddress().getAddress());
            customerDetailBO.setProvince(customer.getAddress().getProvinceName());
            customerDetailBO.setCity(customer.getAddress().getCityName());
            customerDetailBO.setDistrict(customer.getAddress().getDistrictName());
        }

        //客户星级
        customerDetailBO.setCustomerRating(customer.getCustomerRatingCode());

        //查询关联阶段信息
        try {
            List<CustomerDetailProcessBO> customerDetailProcessBOS = queryRelationByCustomerId(customer.getId(), privateSphere);
            customerDetailBO.setStageRelationList(customerDetailProcessBOS);
        } catch (Exception e) {
            log.error("queryCustomerDetail.queryProcessStageRelation,e", e);
        }

        try {
            // 3、查询个人标签信息
            CustomerTagQueryDTO customerTagQueryDTO = new CustomerTagQueryDTO();
            BeanUtils.copyProperties(queryDTO.getBasicInfo(), customerTagQueryDTO);
            customerTagQueryDTO.setExternalUserId(customer.getExternalUserid());
            List<TagBO> tagBOS = tagManageService.queryCustomerTag(customerTagQueryDTO);
            customerDetailBO.setTagDetailList(this.toTagDetailBO(tagBOS));
        } catch (Exception e) {
            log.error("查询客户标签信息数据出错,error", e);
        }


        // 4、查询流失状态
        List<CustomerEmployeeRelation> customerEmployeeRelationList = null;
        try {
            customerEmployeeRelationList = customerServiceProxy.fetchCustomerEmployeeRelation(customer.getId(), null, privateSphere, CustomerStatusEnum.DEFAULT, true, null);
        } catch (Exception e) {
            log.error("查询客户好友信息数据出错,error", e);
        }

        if (CollectionUtils.isNotEmpty(customerEmployeeRelationList)) {
            customerDetailBO.setFriendCount(customerEmployeeRelationList.size());
            customerDetailBO.setFlowStatus(false);

            // 查询当前员工添加时间及方式
            if (StringUtils.isNotBlank(queryDTO.getUserId())) {
                Employee employee = employeeProxy.fetchEmployeeById(privateSphere, queryDTO.getUserId(), null);
                if (employee != null) {
                    CustomerEmployeeRelation relation = customerEmployeeRelationList.stream().filter(item -> StringUtils.equals(item.getEmployee().getId(), employee.getId())).findFirst().orElse(null);
                    if (relation != null) {
                        if (relation.getAddWay() != null) {
                            customerDetailBO.setAddWayDesc(relation.getAddWay().getDesc());
                        }
                        if (relation.getSubAddWay() != null) {
                            customerDetailBO.setSubAddWayDesc(relation.getSubAddWay().getDesc());
                        }
                        if (relation.getAddTime() != null) {
                            customerDetailBO.setLatestAddTime(relation.getAddTime().getTime());
                        }
                    }
                }
            }

        } else {
            customerDetailBO.setFriendCount(0);
            customerDetailBO.setFlowStatus(true);
        }


        CustomerChatGroupDTO customerChatGroupDTO = new CustomerChatGroupDTO();
        customerChatGroupDTO.setBasicInfo(queryDTO.getBasicInfo());
        customerChatGroupDTO.setCustomerId(customer.getId());
        customerChatGroupDTO.setExternalUserId(customer.getExternalUserid());
        customerChatGroupDTO.setPageNum(1);
        customerChatGroupDTO.setPageSize(20);
        PageResponse<CustomerChatGroupBO> groupChatListByMember = groupService.getGroupChatListByMember(customerChatGroupDTO);

        if (groupChatListByMember.getTotalCount() != null) {
            customerDetailBO.setGroupCount(groupChatListByMember.getTotalCount().intValue());
        } else {
            customerDetailBO.setGroupCount(0);
        }

        //5、获取用户wid
        Long wid = customerThird.getSuperWid(privateSphere.getBosId(), customer.getExternalUserid(), privateSphere.getCorpId());
        //wid 为null，无需获取其他外部信息了
        if (Objects.isNull(wid)) {
            log.warn("queryCustomerDetail,客户wid未获取到，externalUserid:{}", customer.getExternalUserid());
            return customerDetailBO;
        }
        customerDetailBO.setExternalUserWid(wid);

        // 6、根据wid查询渠道信息
        try {
            //5、查询各渠道手机号数据、导购数据 CDP基本信息
            CDPUserInfoGetDTO cdpUserInfoGetDTO = new CDPUserInfoGetDTO();
            cdpUserInfoGetDTO.setBosId(queryDTO.getBasicInfo().getBosId());
            cdpUserInfoGetDTO.setWid(wid);
            cdpUserInfoGetDTO.setCorpId(privateSphere.getCorpId());
            CDPUserAttributeBO cdpUserAttributeBO = SoaUtil.unpack(cdpUserAdapterService.getCDPBaseUserInfo(cdpUserInfoGetDTO));
            CDPUserAttributeBO cdpMobileBO = SoaUtil.unpack(cdpUserAdapterService.getCustomerGatherInfo(cdpUserInfoGetDTO));
            if (null != cdpUserAttributeBO) {
                customerDetailBO.setBelongToStoreName(cdpUserAttributeBO.getBelongToStoreName());
                customerDetailBO.setBelongToGuider(cdpUserAttributeBO.getBelongToGuiderName());
            }
            if (null != cdpMobileBO && CollectionUtils.isNotEmpty(cdpMobileBO.getCdpAllMobilesList())) {
                List<String> filterPhone = cdpMobileBO.getCdpAllMobilesList().stream().filter(item -> !StringUtils.equals(item, customerDetailBO.getMobiles())).collect(Collectors.toList());
                customerDetailBO.setCdpMobilesList(filterPhone);
            }

            // 外部联系人账户信息, 余额、积分、优惠券数量
            AccountBO accountBO = queryAccountBO(privateSphere.getBosId(), privateSphere.getProductInstanceId(), wid, privateSphere.getTcode());
            customerDetailBO.setAccountBO(accountBO);


            // 查询账户消费信息
            CDPUserConsumeGetDTO cdpUserConsumeGetDTO = new CDPUserConsumeGetDTO();
            cdpUserConsumeGetDTO.setBosId(queryDTO.getBasicInfo().getBosId());
            cdpUserConsumeGetDTO.setWid(wid);
            CDPUserConsumeGetBO cdpUserConsumeGetBO = SoaUtil.unpack(cdpUserAdapterService.getCDPUserConsumeInfo(cdpUserConsumeGetDTO));
            ConsumeBO consumeBO = new ConsumeBO();
            consumeBO.setTotalConsumeAmount(cdpUserConsumeGetBO.getTotalConsumeAmount());
            consumeBO.setConsumeTimes(cdpUserConsumeGetBO.getConsumeTimes());
            consumeBO.setLatestConsumeTime(cdpUserConsumeGetBO.getLatestConsumeTime());
            customerDetailBO.setConsumeBO(consumeBO);


            //7.3、查询账户会员卡信息
            CDPMemberCardGetDTO cdpMemberCardGetDTO = new CDPMemberCardGetDTO();
            cdpMemberCardGetDTO.setBosId(privateSphere.getBosId());
            cdpMemberCardGetDTO.setWid(wid);
            cdpMemberCardGetDTO.setPageNum(1);
            cdpMemberCardGetDTO.setPageSize(100);
            PageInfoResponse<CDPMemberCardGetBO> memberCard = SoaUtil.unpack(cdpUserAdapterService.getCDPMemberCardInfo(cdpMemberCardGetDTO));
            List<MemberBO> memberBOS = new ArrayList<>();
            if (CollectionUtils.isNotEmpty(memberCard.getDataList())) {
                for (CDPMemberCardGetBO cdpMemberCardGetBO : memberCard.getDataList()) {
                    MemberBO memberBO = new MemberBO();

                    String memberCardTemplateId = cdpMemberCardGetBO.getMemberCardTemplateId();
                    if (StringUtils.isNotBlank(memberCardTemplateId)) {
                        memberBO.setMemberCardTemplateId(Long.parseLong(memberCardTemplateId));
                    }
                    memberBO.setMemberCardLevel(cdpMemberCardGetBO.getMemberCardLevel());
                    memberBO.setMemberCardName(cdpMemberCardGetBO.getMemberCardName());
                    memberBO.setStatus(cdpMemberCardGetBO.getStatus());
                    memberBO.setRankId(cdpMemberCardGetBO.getRankId());

                    memberBO.setMemberCardType(cdpMemberCardGetBO.getMemberCardType());
                    memberBOS.add(memberBO);
                }
            }
            customerDetailBO.setMemberBOS(memberBOS);
        } catch (Exception e) {
            log.error("查询客户CDP基本信息账户会员卡信息数据出错, error", e);
        }
        try {
            if (CollectionUtils.isNotEmpty(ipaasWhiteListBosIds) && ipaasWhiteListBosIds.contains(privateSphere.getBosId())) {
                this.getCustomerCrmByIpaas(privateSphere, queryDTO.getBasicInfo().getVid(), wid, customerDetailBO);
            }
        } catch (Exception e) {
            log.error("通过ipaas查crm信息数据出错, error", e);
        }
        return customerDetailBO;
    }

    private void getCustomerCrmByIpaas(PrivateSphere privateSphere, Long vid, Long wid, CustomerDetailBO customerDetailBO) {
        CustomerAssetCrmAdapterRequest customerAssetCrmAdapterRequest = new CustomerAssetCrmAdapterRequest();
        customerAssetCrmAdapterRequest.setBosId(privateSphere.getBosId());
        customerAssetCrmAdapterRequest.setProductInstanceId(privateSphere.getProductInstanceId());
        customerAssetCrmAdapterRequest.setVid(vid);
        customerAssetCrmAdapterRequest.setWid(wid);
        customerAssetCrmAdapterRequest.setTcode(privateSphere.getTcode());
        try {
            // 会员卡
            List<MemberCardSPIDTO> memberCardList = SoaUtil.unpack(crmAdapterService.getCustomerMemberCard(customerAssetCrmAdapterRequest));
            // 会员卡方案
            if (CollectionUtils.isNotEmpty(memberCardList)) {
                List<MemberBO> memberBOS = new ArrayList<>();
                for (MemberCardSPIDTO memberCardSPIDTO : memberCardList) {

                    MemberBO memberBO = new MemberBO();
                    memberBO.setMemberCardTemplateId(memberCardSPIDTO.getMembershipPlanId());
                    memberBO.setStatus(memberCardSPIDTO.getStatus());
                    memberBO.setRankId(memberCardSPIDTO.getLevelId());


                    customerAssetCrmAdapterRequest.setMembershipPlanId(memberCardSPIDTO.getMembershipPlanId());
                    List<MemberCardPlanSPIDTO> memberCardPlanList = SoaUtil.unpack(crmAdapterService.getCustomerMemberCardPlan(customerAssetCrmAdapterRequest));

                    if (CollectionUtils.isNotEmpty(memberCardPlanList)) {
                        if (CollectionUtils.isNotEmpty(memberCardPlanList.get(0).getLevelInfos())) {
                            MemberCardPlanSPIDTO.LevelInfosBean levelInfosBean = memberCardPlanList.get(0).getLevelInfos().stream().filter(item -> item.getLevelId().equals(memberCardSPIDTO.getLevelId())).findFirst().orElse(null);
                            if (Objects.nonNull(levelInfosBean)) {
                                String levelName = levelInfosBean.getLevelName();
                                memberBO.setMemberCardLevel(levelName);
                            }
                        }
                        memberBO.setMemberCardName(memberCardPlanList.get(0).getName());
                        // paas接口处理，1 代表多级卡 2 代表单机卡 和前端和cdp已有逻辑相反  处理下
                        if (memberCardPlanList.get(0).getCardType() != null) {
                            if (memberCardPlanList.get(0).getCardType().equals(1)) {
                                memberBO.setMemberCardType(2);
                            }
                            if (memberCardPlanList.get(0).getCardType().equals(2)) {
                                memberBO.setMemberCardType(1);
                            }
                        }

                    }

                    memberBOS.add(memberBO);
                }
                customerDetailBO.setMemberBOS(memberBOS);
            }
        } catch (Exception e) {
            log.error("ipass查询客户会员数据出错,error", e);
        }


        AccountBO accountBO = customerDetailBO.getAccountBO();
        // 积分
        try {
            CustomerPointSPIDTO customerPoint = SoaUtil.unpack(crmAdapterService.getCustomerPoint(customerAssetCrmAdapterRequest));
            if (customerPoint != null && customerPoint.getAvailablePoint() != null) {
                accountBO.setBonusPoint(customerPoint.getAvailablePoint() + "");
            }
        } catch (Exception e) {
            log.error("ipass查询客户积分数据出错,error", e);
        }

        // 余额
        try {
            CustomerBalanceSPIDTO customerBalance = SoaUtil.unpack(crmAdapterService.getCustomerBalance(customerAssetCrmAdapterRequest));
            if (customerBalance != null && Objects.nonNull(customerBalance.getTotalAmount())) {
                accountBO.setAccountBalances(customerBalance.getTotalAmount().doubleValue());
            } else {
                accountBO.setAccountBalances(0.0);
            }
        } catch (Exception e) {
            accountBO.setAccountBalances(0.0);
            log.error("ipass查询客户余额数据出错,error", e);
        }
        customerDetailBO.setAccountBO(accountBO);

        // 生日
        try {
            CustomerInfoCrmAdapterRequest customerInfoCrmAdapterRequest = new CustomerInfoCrmAdapterRequest();
            customerInfoCrmAdapterRequest.setBosId(privateSphere.getBosId());
            customerInfoCrmAdapterRequest.setProductInstanceId(privateSphere.getProductInstanceId());
            customerInfoCrmAdapterRequest.setVid(vid);
            customerInfoCrmAdapterRequest.setWidList(Lists.newArrayList(wid));
            customerInfoCrmAdapterRequest.setResultType(Lists.newArrayList(1));
            customerInfoCrmAdapterRequest.setTcode(privateSphere.getTcode());
            CustomerInfoSPIDTO customerInfo = SoaUtil.unpack(crmAdapterService.getCustomerInfo(customerInfoCrmAdapterRequest));
            if (customerInfo != null && CollectionUtils.isNotEmpty(customerInfo.getUserBaseInfoList())) {
                Long birthday = customerInfo.getUserBaseInfoList().get(0).getBirthday();
                if (birthday != null) {
                    customerDetailBO.setBirthday(DateFormatUtils.format(birthday, "yyyy-MM-dd"));
                }
            }
        } catch (Exception e) {
            log.error("ipass查询客户生日数据出错,error", e);
        }

    }


    /**
     * 获取员工userId
     *
     * @param cdpUserLogBOList
     * @return
     */
    private List<String> covert2UserId(List<CDPUserLogBO> cdpUserLogBOList) {
        if (CollectionUtils.isEmpty(cdpUserLogBOList)) {
            return Lists.newArrayList();
        }
        List<String> userIdList = Lists.newArrayList();
        for (CDPUserLogBO cdpUserLogBO : cdpUserLogBOList) {
//            CDPUserLogBO.DataJsonBean dataJsonBean = cdpUserLogBO.getDataJsonBean();
            CdpDataJsonInfo cdpDataJsonInfo = null;
            if (StringUtils.isNotEmpty(cdpUserLogBO.getDataJson())) {
                cdpDataJsonInfo = JSON.parseObject(cdpUserLogBO.getDataJson(), CdpDataJsonInfo.class);
            }
            if (cdpDataJsonInfo == null) {
                continue;
            }
            userIdList.add(cdpDataJsonInfo.getOrgUserId());
        }
        return userIdList;
    }

    /**
     * 构建代金券
     *
     * @param userBehaviorDTO
     * @return
     */
    private CouponMarkInfo buildCoupon(UserBehaviorDTO userBehaviorDTO) {
        List<String> couponType = Lists.newArrayList("1", "2", "3", "5", "9");
        if (Objects.isNull(userBehaviorDTO) || !couponType.contains(userBehaviorDTO.getCouponType())) {
            return null;
        }
        //优惠券
        CouponMarkInfo coupon = new CouponMarkInfo();
        coupon.setCouponName(userBehaviorDTO.getCouponName());

        //优惠券权使用说明
        if (StringUtils.isNotEmpty(userBehaviorDTO.getUseThreshold())) {
            Double useThreshold = Double.valueOf(userBehaviorDTO.getUseThreshold()) / 100;
            coupon.setCouponDescription("满" + useThreshold + "元可用");
        } else {
            coupon.setCouponDescription("满0元可用");
        }
        if (userBehaviorDTO.getCouponUseAmount() != null) {
            coupon.setCouponDiscount(Double.valueOf(userBehaviorDTO.getCouponUseAmount()) / 100);
        }


        //券面值-折扣金额
        if (userBehaviorDTO.getCouponUseAmount() != null) {
            coupon.setCouponReduceCost(Double.valueOf(userBehaviorDTO.getCouponUseAmount()) / 100);
        }

        //有效期开始时间
        String couponStartDate = userBehaviorDTO.getUseStartTime();
        if (Objects.nonNull(couponStartDate)) {
            coupon.setCouponStartDate(DateUtils.getToLong(couponStartDate));
        }

        //有效期截止时间
        String couponExpDate = userBehaviorDTO.getUseEndTime();
        if (Objects.nonNull(couponExpDate)) {
            coupon.setCouponExpDate(DateUtils.getToLong(couponExpDate));
        }

        //优惠券类型
        if (userBehaviorDTO.getCouponType() != null) {
            coupon.setCouponType(Integer.valueOf(userBehaviorDTO.getCouponType()));
        }
        return coupon;
    }

    /**
     * 构建商品相关
     *
     * @param userBehaviorDTO
     * @return
     */
    private ProductMarkDomain buildProduct(UserBehaviorDTO userBehaviorDTO) {
        if (Objects.isNull(userBehaviorDTO)) {
            return null;
        }

        ProductMarkDomain product = new ProductMarkDomain();
        String goodsMainImageUrlList = userBehaviorDTO.getGoodsMainImageUrlList();
        if (StringUtils.isNotBlank(goodsMainImageUrlList)) {
            List<String> goodsMainImageUrls = JSON.parseArray(goodsMainImageUrlList, String.class);
            if (CollectionUtils.isNotEmpty(goodsMainImageUrls)) {
                product.setPicUrl(goodsMainImageUrls.get(0));
            }
        }
        BigDecimal goodMainPrice = userBehaviorDTO.getGoodsPrice();
        if (Objects.nonNull(goodMainPrice)) {
            product.setPrice(goodMainPrice.doubleValue());
        }
        product.setProductName(userBehaviorDTO.getGoodsName());
        product.setSpecifications(userBehaviorDTO.getSkuName());
        return product;

    }

    /**
     * 构建订单相关
     *
     * @param userBehaviorDTO
     * @return
     */
    private OrderMarkInfo buildOrder(UserBehaviorDTO userBehaviorDTO) {
        if (Objects.isNull(userBehaviorDTO)) {
            return null;
        }

        ProductMarkDomain product = new ProductMarkDomain();
        String goodsMainImageUrlList = userBehaviorDTO.getGoodsMainImageUrlList();
        if (StringUtils.isNotBlank(goodsMainImageUrlList)) {
            List<String> goodsMainImageUrls = JSON.parseArray(goodsMainImageUrlList, String.class);
            if (CollectionUtils.isNotEmpty(goodsMainImageUrls)) {
                product.setPicUrl(goodsMainImageUrls.get(0));
            }
        }


        String goodsTitles = userBehaviorDTO.getGoodsTitleList();
        if (StringUtils.isNotBlank(goodsTitles)) {
            List<String> goodsTitleList = JSON.parseArray(goodsTitles, String.class);
            if (CollectionUtils.isNotEmpty(goodsTitleList)) {
                product.setProductName(goodsTitleList.get(0));
            }
        }


        //下单商品规格
        String goodsSkuNames = userBehaviorDTO.getSkuNameList();
        if (StringUtils.isNotBlank(goodsSkuNames)) {
            List<String> goodsSkuNameList = JSON.parseArray(goodsSkuNames, String.class);
            if (CollectionUtils.isNotEmpty(goodsSkuNameList)) {
                product.setSpecifications(goodsSkuNameList.get(0));
            }
        }


        OrderMarkInfo order = new OrderMarkInfo();
        //下单商品数量
        String goodsSkuNums = userBehaviorDTO.getSkuNumList();
        if (StringUtils.isNotBlank(goodsSkuNums)) {
            List<Long> goodsSkuNumList = JSON.parseArray(goodsSkuNums, Long.class);
            if (CollectionUtils.isNotEmpty(goodsSkuNumList)) {
                Long num = goodsSkuNumList.stream().reduce(Long::sum).orElse(0L);
                order.setProductNum(num);
            }

        }
        //订单号
        order.setOrderNo(userBehaviorDTO.getOrderId());

        //订单总金额
        BigDecimal orderPaymentAmount = userBehaviorDTO.getPayAmt();
        if (Objects.nonNull(orderPaymentAmount)) {
            order.setTotalPrice(orderPaymentAmount.doubleValue());
        }

        order.setProductList(Lists.newArrayList(product));
        return order;

    }

    /**
     * 构建活动
     *
     * @param userBehaviorDTO
     * @return
     */
    private ActivityMarkInfo buildActivity(UserBehaviorDTO userBehaviorDTO, String eventType) {
        if (Objects.isNull(userBehaviorDTO)) {
            return null;
        }
        ActivityMarkInfo activityMarkVO = new ActivityMarkInfo();
        activityMarkVO.setActivityName(userBehaviorDTO.getAtyName());
        // 贼恶心 cdp那边浏览促销活动也过来的字段名不一样
        if (CdpMarkMessageEventEnum.BROWSE_GOODS_PROMOTION.getEventType().equals(eventType)) {
            activityMarkVO.setActivityName(userBehaviorDTO.getActivityName());
        }
        activityMarkVO.setPageTitle(userBehaviorDTO.getPageTitle());
        if (StringUtils.isEmpty(activityMarkVO.getActivityName())) {
            activityMarkVO.setActivityName(userBehaviorDTO.getPageTitle());
        }

        return activityMarkVO;

    }

    /**
     * 构建雷达
     *
     * @param userBehaviorDTO
     * @return
     */
    private RadarMarkInfo buildRadar(UserBehaviorDTO userBehaviorDTO, String eventType, RadarRelatedInfoDTO radarRelatedInfoDTO, String externalUserId) {
        if (Objects.nonNull(userBehaviorDTO) && Objects.nonNull(radarRelatedInfoDTO)
                && (CdpMarkMessageEventEnum.CLICK_RADAR.getEventType().equals(eventType)
                || CdpMarkMessageEventEnum.EXIT_RADAR.getEventType().equals(eventType))) {
            String radarId = userBehaviorDTO.getRadarId();
            RadarConfigDetailBO radarConfigDetailBO = radarRelatedInfoDTO.getRadarMap().get(radarId);
            if (Objects.nonNull(radarConfigDetailBO)) {
                RadarMarkInfo radarMarkInfo = new RadarMarkInfo();
                radarMarkInfo.setTitle(radarConfigDetailBO.getTitle());
                if (StringUtils.isNotBlank(radarRelatedInfoDTO.getUrlPrefix())) {
                    String titleUrl = radarRelatedInfoDTO.getUrlPrefix() + "&radarId=" + radarId;
                    radarMarkInfo.setTitleUrl(titleUrl);
                }
                radarMarkInfo.setPgStayLength(userBehaviorDTO.getPgStayLength());
                radarMarkInfo.setReadPercent(userBehaviorDTO.getReadPercent());

                // 客户分享
                if (Objects.nonNull(userBehaviorDTO.getFromWid())) {
                    ExternalUserListBO externalUserListBO = radarRelatedInfoDTO.getExternalUserMap().get(Long.parseLong(userBehaviorDTO.getFromWid()));
                    String name = "";
                    if (Objects.nonNull(externalUserListBO)) {
                        name = externalUserListBO.getExternalUserName();
                    }
                    radarMarkInfo.setSource((String.format(CUSTOMER_SOURCE_STR, name)));
                } else if (Objects.nonNull(userBehaviorDTO.getStaffId())) {
                    // 员工分享
                    String employeeName = "";
                    String sendScene = "";
                    Employee employee = radarRelatedInfoDTO.getEmployeeMap().get(userBehaviorDTO.getStaffId());
                    ShortURLSendSceneEnum urlSendSceneEnum = ShortURLSendSceneEnum.getEnumByValue(userBehaviorDTO.getSendScene());
                    if (Objects.nonNull(employee)) {
                        employeeName = employee.getName();
                    }
                    if (Objects.nonNull(urlSendSceneEnum)) {
                        sendScene = urlSendSceneEnum.getDesc();
                    }
                    radarMarkInfo.setSource((String.format(EMPLOYEE_SOURCE_STR, employeeName, sendScene)));
                }
                return radarMarkInfo;
            }
        }
        return null;
    }

    /**
     * 批量获取雷达相关信息（雷达，员工，客户）
     *
     * @param cdpUserLogBOList
     * @return
     */
    private RadarRelatedInfoDTO batchGetRadarRelatedInfo(List<CDPUserLogBO> cdpUserLogBOList, PrivateSphere privateSphere, BasicInfo basicInfo) {
        Map<String, RadarConfigDetailBO> radarMap = new HashMap<>();
        Map<String, Employee> employeeMap = new HashMap<>();
        Map<Long, ExternalUserListBO> externalUserMap = new HashMap<>();

        if (!CollectionUtils.isEmpty(cdpUserLogBOList)) {
            List<UserBehaviorDTO> userBehaviorDTOList = cdpUserLogBOList.stream()
                    .filter((e) -> CdpMarkMessageEventEnum.CLICK_RADAR.getEventType().equals(e.getEventType()) || CdpMarkMessageEventEnum.EXIT_RADAR.getEventType().equals(e.getEventType()))
                    .map(CDPUserLogBO::getUserBehaviorDTO)
                    .collect(Collectors.toList());

            if (!CollectionUtils.isEmpty(userBehaviorDTOList)) {
                // 批量获取雷达信息
                radarMap = radarProxy.findRadarByIds(cdpUserLogBOList, privateSphere.getCorpId(), basicInfo);
                if (radarMap == null || radarMap.isEmpty()) {
                    return null;
                }

                List<String> employeeIdList = userBehaviorDTOList.stream().map(UserBehaviorDTO::getStaffId).collect(Collectors.toList());
                // 批量获取员工信息
                if (!CollectionUtils.isEmpty(employeeIdList)) {
                    employeeMap = queryOrgUserBO(employeeIdList, privateSphere);
                }
                // 批量获取客户信息
                List<Long> widList = Lists.newArrayList();
                for (UserBehaviorDTO userBehaviorDTO : userBehaviorDTOList) {
                    if (StringUtils.isNotBlank(userBehaviorDTO.getUkey())) {
                        widList.add(Long.parseLong(userBehaviorDTO.getUkey()));
                    }
                    if (StringUtils.isNotBlank(userBehaviorDTO.getFromWid())) {
                        widList.add(Long.parseLong(userBehaviorDTO.getFromWid()));
                    }
                }
                if (!CollectionUtils.isEmpty(widList)) {
                    List<ExternalUserListBO> externalUserList = getExternalUserInfoByWids(privateSphere, widList, null, false);
                    if (!CollectionUtils.isEmpty(externalUserList)) {
                        externalUserMap = externalUserList.stream().collect(Collectors.toMap(ExternalUserListBO::getExternalUserWid, Function.identity(), (k1, k2) -> k1));
                    }
                }
                // 获取雷达标题url前缀
                String url = radarProxy.generateURL(basicInfo);
                RadarRelatedInfoDTO radarRelatedInfoDTO = new RadarRelatedInfoDTO();
                radarRelatedInfoDTO.setRadarMap(radarMap);
                radarRelatedInfoDTO.setEmployeeMap(employeeMap);
                radarRelatedInfoDTO.setExternalUserMap(externalUserMap);
                radarRelatedInfoDTO.setUrlPrefix(url);

                return radarRelatedInfoDTO;
            }
        }
        return null;
    }

    /**
     * 获取员工信息
     *
     * @param employeeIds
     * @param
     * @return
     */
    private Map<String, Employee> queryOrgUserBO(List<String> employeeIds, PrivateSphere privateSphere) {
        //根据用户名称查询userId
        if (CollectionUtils.isEmpty(employeeIds)) {
            return Maps.newHashMap();
        }

        List<Employee> employeeResDTOList = employeeProxy.getByEmployeeIdOrTxUserIds(privateSphere, employeeIds, null).getDataList();
        if (CollectionUtils.isEmpty(employeeResDTOList)) {
            return Maps.newHashMap();
        }

        Map<String, Employee> map = Maps.newHashMap();
        for (Employee orgUserBO : employeeResDTOList) {
            map.put(orgUserBO.getId(), orgUserBO);
        }
        return map;
    }

    public PageResponse<CustomerLogBO> findCustomerLog(CustomerLogFindDTO dto) {
        //0.根据basicInfo，换取私域
        PrivateSphere privateSphere = privateSphereThird.fetch(dto.getBasicInfo(), true);

        // 兼容活码过来没externaluserId
        if (StringUtils.isEmpty(dto.getExternalUserId())) {
            try {
                String customerId = dto.getCustomerId();
                if (StringUtils.isBlank(customerId)) {
                    return new PageResponse<>();
                }
                List<Customer> customerList = customerServiceProxy.fetchCustomerByIds(customerId, null, privateSphere);

                if (CollectionUtils.isEmpty(customerList)) {
                    return new PageResponse<>();
                }

                dto.setExternalUserId(customerList.get(0).getExternalUserid());
            } catch (Exception e) {
                log.error("findCustomerLog error", e);
                return new PageResponse<>();
            }
        }

        Long wid = customerThird.getSuperWid(dto.getBasicInfo().getBosId(), dto.getExternalUserId(), privateSphere.getCorpId());
        //避免wid为空，可能wid注销了
        if (Objects.isNull(wid)) {
            return new PageResponse<>();
        }
        PageResponse<CustomerLogBO> pageResponse = new PageResponse();
        pageResponse.setPageNum(dto.getPageNum());
        pageResponse.setPageSize(dto.getPageSize());

        CDPUserLogFindDTO cdpUserLogFindDTO = new CDPUserLogFindDTO();
        cdpUserLogFindDTO.setBosId(dto.getBasicInfo().getBosId());
        cdpUserLogFindDTO.setWid(wid);
        if (dto.getActionTime() != null) {
            cdpUserLogFindDTO.setStartTime(dto.getActionTime());
            cdpUserLogFindDTO.setEndTime(dto.getActionTime() + 24 * 60 * 60 * 1000);
        }

        cdpUserLogFindDTO.setEventTypeList(Sets.newHashSet(CdpMarkMessageEventEnum.CUSTOMER_DEL_USER.getEventType(),
                CdpMarkMessageEventEnum.CUSTOMER_DEL_USER.getEventType(),
                CdpMarkMessageEventEnum.ADD_FRIEND.getEventType(),
                CdpMarkMessageEventEnum.REDPACKAGE_GROUP_RECEIVE.getEventType(),
                CdpMarkMessageEventEnum.REDPACKAGE_PERSONAL_RECEIVE.getEventType(),
                CdpMarkMessageEventEnum.BROWSE_FRIEND_CIRCLE.getEventType(),
                CdpMarkMessageEventEnum.CHANGE_STORE.getEventType(),
                CdpMarkMessageEventEnum.SEARCH.getEventType(),
                CdpMarkMessageEventEnum.BROWSE_GOODS.getEventType(),
                CdpMarkMessageEventEnum.PV.getEventType(),
                CdpMarkMessageEventEnum.VIEW.getEventType(),
                CdpMarkMessageEventEnum.BROWSE_INTERACTIVE.getEventType(),
                CdpMarkMessageEventEnum.BROWSE_CONTENT_ACTIVITY.getEventType(),
                CdpMarkMessageEventEnum.CART.getEventType(),
                CdpMarkMessageEventEnum.GET_COUPON.getEventType(),
                CdpMarkMessageEventEnum.SERVICE_SUBMIT_ORDER.getEventType(),
                CdpMarkMessageEventEnum.SERVICE_FINISH_ORDER.getEventType(),
                CdpMarkMessageEventEnum.SERVICE_CANCEL_ORDER.getEventType(),
                CdpMarkMessageEventEnum.SERVICE_AFTER_SALES.getEventType(),
                CdpMarkMessageEventEnum.JOIN_GROUP.getEventType(),
                CdpMarkMessageEventEnum.QUIT_GROUP.getEventType(),
                CdpMarkMessageEventEnum.JOIN.getEventType(),
                CdpMarkMessageEventEnum.MISSION_S.getEventType(),
                CdpMarkMessageEventEnum.CLICK_RADAR.getEventType(),
                CdpMarkMessageEventEnum.EXIT_RADAR.getEventType()
        ));
        cdpUserLogFindDTO.setPageNum(dto.getPageNum());
        cdpUserLogFindDTO.setPageSize(dto.getPageSize());


        com.weimob.mcloud.wechatwork.core.adapter.pojo.dto.page.PageInfoResponse<CDPUserLogBO> cdpPageResponse =
                SoaUtil.unpack(cdpUserAdapterService.findCDPUserLogList(cdpUserLogFindDTO));
        if (CollectionUtils.isEmpty(cdpPageResponse.getDataList())) {
            return new PageResponse<>(new ArrayList<>(), dto.getPageNum(), dto.getPageSize(), 0L);
        }
        List<CDPUserLogBO> cdpUserLogBOList = cdpPageResponse.getDataList();

        // 批量查询雷达相关（雷达，员工，客户）信息
        RadarRelatedInfoDTO radarRelatedInfoDTO = batchGetRadarRelatedInfo(cdpUserLogBOList, privateSphere, dto.getBasicInfo());

        //获取userId
        List<String> userList = covert2UserId(cdpUserLogBOList);
        //根据用户名称查询userId,key:userId, value:OrgUserBO

        //String corpid = this.getPrivateSphereByBasicInfo(dto.getBasicInfo()).getCorpId();

        Map<String, Employee> orgUserBOMap = queryOrgUserBO(userList, privateSphere);
        List<CustomerLogBO> resultList = Lists.newArrayList();
        for (CDPUserLogBO result : cdpUserLogBOList) {
            CustomerLogBO externalUserLogFindVO = new CustomerLogBO();
            CdpDataJsonInfo cdpDataJsonInfo = new CdpDataJsonInfo();
            if (StringUtils.isNotEmpty(result.getDataJson())) {
                cdpDataJsonInfo = JSON.parseObject(result.getDataJson(), CdpDataJsonInfo.class);
            }
            externalUserLogFindVO.setActionTime(result.getActionTime());

            //设置事件类型
            CdpMarkMessageEventEnum eventType = CdpMarkMessageEventEnum.getEnumByEventType(result.getEventType());
            if (null == eventType) {
                continue;
            }

            // 新云和wos eventType映射
            if (CdpMarkMessageEventEnum.PV.getEventType().equals(eventType.getEventType())) {
                // 浏览商品
                if (result.getUserBehaviorDTO() != null &&
                        (CDPPageNameEnum.EC_GOODS_DETAIL.getName().equals(result.getUserBehaviorDTO().getPageName())) || CDPPageNameEnum.HUOD_HOME.getName().equals(result.getUserBehaviorDTO().getPageName())) {
                    eventType = CdpMarkMessageEventEnum.BROWSE_GOODS;
                }

                // 浏览商品促销活动页
                if (String.valueOf(WosProductType.SHOP.getProductId()).equals(result.getSChannelType()) && StringUtils.isNotEmpty(result.getUserBehaviorDTO().getActivityId()) && StringUtils.isNotEmpty(result.getUserBehaviorDTO().getActivityType())) {
                    eventType = CdpMarkMessageEventEnum.BROWSE_GOODS_PROMOTION;
                }

                // ①浏览互动营销活动页
                if (result.getUserBehaviorDTO() != null &&
                        (CDPPageNameEnum.ATY_HOME.getName().equals(result.getUserBehaviorDTO().getPageName())) || CDPPageNameEnum.HUOD_HOME.getName().equals(result.getUserBehaviorDTO().getPageName())) {
                    eventType = CdpMarkMessageEventEnum.BROWSE_INTERACTIVE;
                }

                // 浏览内容主题页
                if (result.getUserBehaviorDTO() != null && String.valueOf(WosProductType.FRAMEWORK_SERVICE.getProductId()).equals(result.getSChannelType()) &&
                        (CDPPageNameEnum.CMS_INDEX.getName().equals(result.getUserBehaviorDTO().getPageName()) || CDPPageNameEnum.CMS_DESIGN.getName().equals(result.getUserBehaviorDTO().getPageName()))) {
                    eventType = CdpMarkMessageEventEnum.BROWSE_CONTENT_ACTIVITY;
                }

            }


            // ②浏览互动营销活动页 答题吃鸡
            if (CdpMarkMessageEventEnum.VIEW.getEventType().equals(eventType.getEventType())) {
                eventType = CdpMarkMessageEventEnum.BROWSE_INTERACTIVE;
            }
            // 上游变动 给前端兼容下 别骂
            if (CdpMarkMessageEventEnum.SERVICE_SUBMIT_ORDER.getEventType().equals(eventType.getEventType())) {
                eventType = CdpMarkMessageEventEnum.SUBMIT_ORDER;
            }

            if (CdpMarkMessageEventEnum.SERVICE_FINISH_ORDER.getEventType().equals(eventType.getEventType())) {
                eventType = CdpMarkMessageEventEnum.ORDER_COMPLETE;
            }

            if (CdpMarkMessageEventEnum.SERVICE_CANCEL_ORDER.getEventType().equals(eventType.getEventType())) {
                eventType = CdpMarkMessageEventEnum.ORDER_OPERATION_CANCEL;
            }

            if (CdpMarkMessageEventEnum.SERVICE_AFTER_SALES.getEventType().equals(eventType.getEventType())) {
                eventType = CdpMarkMessageEventEnum.APPLY_RIFHTS;
            }


            externalUserLogFindVO.setEventType(eventType.getEventType());

            //员工名称
            String username = null;
            if (Objects.nonNull(cdpDataJsonInfo)) {
                if (StringUtils.isNotEmpty(cdpDataJsonInfo.getOrgUserName())) {
                    username = cdpDataJsonInfo.getOrgUserName();
                } else {
                    Employee employee = orgUserBOMap.get(cdpDataJsonInfo.getOrgUserId());
                    if (employee != null) {
                        username = employee.getName();
                    }
                }
            }
            externalUserLogFindVO.setOrgUserName(username);

            //获取打点记录
            UserBehaviorRecord userBehaviorRecordVO = new UserBehaviorRecord();
            userBehaviorRecordVO.setUserName(username);
            if (Objects.nonNull(cdpDataJsonInfo)) {
                userBehaviorRecordVO.setExternalUserName(cdpDataJsonInfo.getWechatNickName());
                userBehaviorRecordVO.setValue(cdpDataJsonInfo.getAddWayDesc());
            }

            UserBehaviorDTO userBehaviorDTO = result.getUserBehaviorDTO();
            if (Objects.nonNull(userBehaviorDTO)) {
                userBehaviorRecordVO.setStoreName(userBehaviorDTO.getStoreName());
                userBehaviorRecordVO.setFromStoreName(userBehaviorDTO.getStoreName());
                userBehaviorRecordVO.setToStoreName(userBehaviorDTO.getGlobalStoreName());
            }

            //代金券相关
            userBehaviorRecordVO.setCoupon(buildCoupon(result.getUserBehaviorDTO()));

            //商品相关
            userBehaviorRecordVO.setProduct(buildProduct(result.getUserBehaviorDTO()));

            //订单相关
            userBehaviorRecordVO.setOrder(buildOrder(result.getUserBehaviorDTO()));

            //活动相关
            userBehaviorRecordVO.setActivity(buildActivity(result.getUserBehaviorDTO(), eventType.getEventType()));

            //雷达相关
            userBehaviorRecordVO.setRadar(buildRadar(result.getUserBehaviorDTO(), eventType.getEventType(), radarRelatedInfoDTO, dto.getExternalUserId()));

            //根据类型特殊处理
            CdpMarkRecordCommonService.handleSpecialCdpMarkRecord(result.getUserBehaviorDTO(), userBehaviorRecordVO, eventType);
            externalUserLogFindVO.setLogDescJson(JSON.toJSONString(userBehaviorRecordVO));

            if (redpackageEnumsLists.contains(eventType)) {
                //小红包的逻辑
                externalUserLogFindVO.setEventTypeDesc(eventType.getDesc());
                if (Objects.nonNull(cdpDataJsonInfo)) {
                    externalUserLogFindVO.setActionDesc(String.format(eventType.getLogDesc(),
                            cdpDataJsonInfo.getWechatNickName(), cdpDataJsonInfo.getOrgUserName(), cdpDataJsonInfo.getAddValue()));
                } else {
                    externalUserLogFindVO.setActionDesc(eventType.getDesc());
                }

                resultList.add(externalUserLogFindVO);
                continue;
            }

            externalUserLogFindVO.setEventTypeDesc(eventType.getDesc());
            if (StringUtils.isNotBlank(username)) {
                externalUserLogFindVO.setActionDesc(String.format(eventType.getLogDesc(), username));
            } else {
                externalUserLogFindVO.setActionDesc(eventType.getDesc());
            }

            externalUserLogFindVO.setLogDescJson(JSON.toJSONString(userBehaviorRecordVO));
            resultList.add(externalUserLogFindVO);
        }
        pageResponse.setResults(resultList);

        pageResponse.setTotalCount(cdpPageResponse.getTotalCount());

        return pageResponse;
    }

    public PageResponse<CustomerActionLogBO> findCorpActionLog(CorpActionLogFindDTO dto) {
        if (null == dto) {
            return new PageResponse<>();
        }
        BasicInfo basicInfo = dto.getBasicInfo();
        if (null == basicInfo || null == basicInfo.getBosId()) {
            return new PageResponse<>();
        }
        PrivateSphere privateSphere = privateSphereThird.fetch(basicInfo, true);

        ActionLog actionLog = new ActionLog();
        actionLog.setCorpId(privateSphere.getCorpId());
        actionLog.setPrivateSphereId(privateSphere.getPrivateSphereId());

        String follower = dto.getFollower();
        if (StringUtils.isNotBlank(follower)) {
            Customer customer = new Customer();
            customer.setId(follower);
            actionLog.setFollower(customer);
        }

        if (dto.getBizType() != null) {
            actionLog.setBizType(ActionLogBizeTypeEnum.getEnumByValue(dto.getBizType()));
        }

        String master = dto.getMaster();
        if (StringUtils.isNotBlank(master)) {
            Employee employee = new Employee();
            employee.setId(master);
            actionLog.setMaster(employee);
        }

        actionLog.setActionValue(dto.getActionValue());
        actionLog.setPromoter(dto.getPromoter());

        SingleRequest<ActionLog> singleRequest = new SingleRequest<>(actionLog, dto.getPageNum(), dto.getPageSize());
        singleRequest.setDateRangeBegin(dto.getStartActionTime());
        singleRequest.setDateRangeEnd(dto.getEndActionTime());

        // 查跟进记录
        MultiResponse<ActionLog> unpack = SoaUtil.unpack(customerService.fetchActionLog(singleRequest));


        // 查员工姓名
        Set<String> employeeIds = new HashSet<>();
        Map<String, Employee> employeeResMap = Maps.newHashMap();
        if (!CollectionUtils.isEmpty(unpack.getDataList())) {
            for (ActionLog actionLogItem : unpack.getDataList()) {
                if (actionLogItem.getMaster() != null) {
                    employeeIds.add(actionLogItem.getMaster().getId());
                }
                if (actionLogItem.getPromoter() != null) {
                    employeeIds.add(actionLogItem.getPromoter());
                }
            }
            MultiResponse<Employee> multiResponse = employeeProxy.getByEmployeeIdOrTxUserIds(privateSphere, Lists.newArrayList(employeeIds), null, true, true);
            if (Objects.isNull(multiResponse) || CollectionUtils.isEmpty(multiResponse.getDataList())) {
                return new PageResponse<>();
            }
            List<Employee> employeeList = multiResponse.getDataList();

            employeeResMap = employeeList.stream().collect(Collectors.toMap(PrivateSphereRelation::getId, v -> v, (v1, v2) -> v1));
        }


        List<CustomerActionLogBO> customerActionLogBOList = new ArrayList<>();
        for (ActionLog actionLogItem : unpack.getDataList()) {
            CustomerActionLogBO customerActionLogBO = this.toActionLogBO(actionLogItem);

            // 区分事件
            if (actionLogItem.getEventType() != null && ActionLogEventTypeEnum.CORP_CHAT_KEYWORK_TAG.getCode().equals(actionLogItem.getEventType().getCode())) {
                customerActionLogBO.setOrgUserName(actionlogDefaultOrgName);
            } else {
                if (StringUtils.isNotEmpty(customerActionLogBO.getMaster())) {
                    Employee employee = employeeResMap.get(customerActionLogBO.getMaster());
                    if (employee != null) {
                        customerActionLogBO.setOrgUserName(employee.getName());
                        if (CollectionUtils.isNotEmpty(employee.getGuiderList())) {
                            customerActionLogBO.setHaveBindGuide(true);
                        } else {
                            customerActionLogBO.setHaveBindGuide(false);
                        }
                    }
                }
            }
            String promoter = actionLogItem.getPromoter();
            if (StringUtils.isNotBlank(promoter)) {
                Employee employee = employeeResMap.get(customerActionLogBO.getPromoter());
                if (Objects.nonNull(employee)) {
                    //id换成人名
                    customerActionLogBO.setPromoter(employee.getName());
                }
            }
            customerActionLogBOList.add(customerActionLogBO);
        }

        return new PageResponse<>(customerActionLogBOList,
                unpack.getPageNum(), unpack.getPageSize(), unpack.getTotalCount());
    }

    private CustomerActionLogBO toActionLogBO(ActionLog actionLogItem) {
        CustomerActionLogBO customerActionLogBO = new CustomerActionLogBO();
        customerActionLogBO.setId(Long.parseLong(actionLogItem.getId()));
        if (actionLogItem.getMaster() != null) {
            customerActionLogBO.setMaster(actionLogItem.getMaster().getId());
        }
        if (actionLogItem.getFollower() != null) {
            customerActionLogBO.setFollower(actionLogItem.getFollower().getId());
        }
        if (actionLogItem.getBizType() != null) {
            customerActionLogBO.setBizType(actionLogItem.getBizType().getCode());
        }
        if (actionLogItem.getEventType() != null) {
            customerActionLogBO.setEventType(actionLogItem.getEventType().getCode());
        }
        customerActionLogBO.setActionTime(actionLogItem.getActionTime());
        customerActionLogBO.setActionValue(actionLogItem.getActionValue());
        customerActionLogBO.setActionDesc(actionLogItem.getActionDesc());
        customerActionLogBO.setPromoter(actionLogItem.getPromoter());
        customerActionLogBO.setFileInfo(actionLogItem.getFileInfo());
        return customerActionLogBO;
    }

    public CustomerActionLogBO addActionLog(CorpActionLogInsertDTO dto) {
        //0.根据basicInfo，换取私域
        PrivateSphere privateSphere = privateSphereThird.fetch(dto.getBasicInfo(), true);

        // 查employeeId
        Employee employee = new Employee();
        if (StringUtils.isEmpty(dto.getOrgUserId()) && StringUtils.isNotEmpty(dto.getTxTuserId())) {
            Employee employeeData = employeeProxy.fetchEmployeeById(privateSphere, dto.getTxTuserId(), null);
            if (employeeData != null) {
                employee.setId(employeeData.getId());
            }
        } else {
            employee.setId(dto.getOrgUserId());
        }

        //1、获取corpId（查询都依赖corpID)
        ActionLog actionLog = new ActionLog();
        actionLog.setCorpId(privateSphere.getCorpId());
        actionLog.setPrivateSphereId(privateSphere.getPrivateSphereId());
        actionLog.setMaster(employee);
        Customer customer = new Customer();
        customer.setId(dto.getCustomerId());
        actionLog.setFollower(customer);

        if (dto.getBizType() != null) {
            actionLog.setBizType(ActionLogBizeTypeEnum.getEnumByValue(dto.getBizType()));
            actionLog.setActionValue(dto.getActionValue());
            // 如果是活码/锁客码，只更新时间，不去插入
            if (ActionLogBizeTypeEnum.STATE_RECORD.getCode().equals(dto.getBizType()) ||
                    ActionLogBizeTypeEnum.LOCK_CODE.getCode().equals(dto.getBizType())) {
                SingleRequest<ActionLog> actionLogSingleRequest = new SingleRequest<>(actionLog);
                MultiResponse<ActionLog> unpack = SoaUtil.unpack(customerService.fetchActionLog(actionLogSingleRequest));
                if (CollectionUtils.isNotEmpty(unpack.getDataList())) {
                    ActionLog updateActionLog = unpack.getDataList().get(0);
                    updateActionLog.setActionTime(dto.getActionTime());
                    updateActionLog.setPromoter(dto.getPromoter());
                    customerService.updateActionLog(updateActionLog);
                    return this.toActionLogBO(unpack.getDataList().get(0));
                }
            }
        }
        if (dto.getEventType() != null) {
            actionLog.setEventType(ActionLogEventTypeEnum.getEnumByCode(dto.getEventType()));
        }
        actionLog.setActionTime(dto.getActionTime());
        actionLog.setActionValue(dto.getActionValue());
        actionLog.setActionDesc(dto.getActionDesc());
        actionLog.setPromoter(dto.getPromoter());

        actionLog = SoaUtil.unpack(customerService.createActionLog(actionLog));

        CustomerActionLogBO customerActionLogBO = this.toActionLogBO(actionLog);

        return customerActionLogBO;
    }

    public List<DivisionBO> findDivisionList(DivisionFindDTO divisionFindDTO) {

        DivisionRequest divisionRequest = new DivisionRequest();
        divisionRequest.setParentCode(divisionFindDTO.getParentCode());
        divisionRequest.setDegree((byte) divisionFindDTO.getDegree().intValue());
        List<DivisionResponse> unpack = SoaUtil.unpack(addressAdapterService.getDivisionListByParentCode(divisionRequest));

        List<DivisionBO> divisionBOS = this.transformDivision(unpack);
        return divisionBOS;
    }

    private List<DivisionBO> transformDivision(List<DivisionResponse> divisionResponses) {
        List<DivisionBO> response = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(divisionResponses)) {
            for (DivisionResponse divisionResponse : divisionResponses) {
                DivisionBO divisionBO = new DivisionBO();
                divisionBO.setCode(divisionResponse.getCode());
                divisionBO.setName(divisionResponse.getName());
                divisionBO.setLevel(divisionResponse.getLevel());
                divisionBO.setParentCode(divisionResponse.getParentCode());
                if (CollectionUtils.isNotEmpty(divisionResponse.getSubDivisionList())) {
                    divisionBO.setSubDivisionList(transformDivision(divisionResponse.getSubDivisionList()));
                }
                response.add(divisionBO);
            }
        }
        return response;
    }

    /**
     * 客搜回调-流程id和阶段id赋值
     *
     * @param privateSphere
     * @param customerId
     * @param customerSearchCallbackBO
     */
    private void convertProcessStageIds(PrivateSphere privateSphere, String customerId, CustomerSearchCallbackBO customerSearchCallbackBO) {
        //1.获取此客户阶段信息
        CustomerStageRelation stageRelation = new CustomerStageRelation();
        stageRelation.setPrivateSphere(privateSphere);
        stageRelation.setCustomer(stageRelation.toCustomer(customerId));
        stageRelation.setCurrentStage(Boolean.TRUE);

        SingleRequest<CustomerStageRelation> request = new SingleRequest<>(stageRelation);
        MultiResponse<CustomerStageRelation> multiResponse = SoaUtil.unpack(stageRelationService.fetchRelationList(request));
        List<CustomerStageRelation> dataList = multiResponse.getDataList();
        if (CollectionUtils.isEmpty(dataList)) {
            customerSearchCallbackBO.setCustomerProcessIdList(Collections.emptyList());
            customerSearchCallbackBO.setCustomerStageIdList(Collections.emptyList());
            return;
        }
        Set<String> stageIds = new HashSet<>();
        Set<String> processIds = new HashSet<>();
        dataList.forEach(item -> {
            String stageId = item.getStageId();
            String processId = item.getProcessId();
            if (Objects.nonNull(stageId)) {
                stageIds.add(stageId);
            }
            if (Objects.nonNull(processId)) {
                processIds.add(processId);
            }
            customerSearchCallbackBO.setCustomerProcessIdList(new ArrayList<>(processIds));
            customerSearchCallbackBO.setCustomerStageIdList(new ArrayList<>(stageIds));
        });

    }

    public List<CustomerSearchCallbackBO> customerSearchCallback(CustomerSearchCallbackDTO customerSearchCallbackDTO) {
        log.info("customerSearchCallback request:{}", JSON.toJSONString(customerSearchCallbackDTO));

        if (null == customerSearchCallbackDTO || null == customerSearchCallbackDTO.getBosId() ||
                CollectionUtils.isEmpty(customerSearchCallbackDTO.getWids())) {
            log.error("客搜回调客户详情, 参数不合法");
            throw new BizException("客搜回调客户详情, 参数不合法");
        }

        //获取私域
        BasicInfo basicInfo = new BasicInfo();
        basicInfo.setBosId(customerSearchCallbackDTO.getBosId());
        PrivateSphere privateSphere = privateSphereThird.fetch(basicInfo, Boolean.TRUE);

        List<PassPortAccountMappingRes> passPortAccountMappingResList = customerFacadeV2.queryAccountMapping(privateSphere.getCorpId(),
                privateSphere.getBosId(), customerSearchCallbackDTO.getWids());
        if (CollectionUtils.isEmpty(passPortAccountMappingResList)) {
            return new ArrayList<>();
        }

        List<CustomerSearchCallbackBO> list = new ArrayList<>();
        for (PassPortAccountMappingRes accountMappingRes : passPortAccountMappingResList) {
            //填充客搜回调bo
            CustomerSearchCallbackBO customerSearchDetail = fillCustomerSearchCallBackBO(accountMappingRes, privateSphere);
            if (Objects.nonNull(customerSearchDetail)) {
                list.add(customerSearchDetail);
            }
        }

        return list;
    }


    /**
     * 填充客搜回调bo
     *
     * @param accountMappingRes
     * @param privateSphere
     * @return
     */
    private CustomerSearchCallbackBO fillCustomerSearchCallBackBO(PassPortAccountMappingRes accountMappingRes, PrivateSphere privateSphere) {
        String externalUserId = accountMappingRes.getExternalUserId();
        Long wid = accountMappingRes.getWid();
        String corpId = privateSphere.getCorpId();
        Long bosId = privateSphere.getBosId();
        Long productInstanceId = privateSphere.getProductInstanceId();
        //查询客户详情，只有微信客户才会同步到客搜
        Customer customerResult = customerServiceProxy.fetchCustomer(null, externalUserId, privateSphere, ExternalUserTypeEnum.WECHAT_CUSTOMER);
        if (customerResult == null) {
            return null;
        }

        CustomerSearchCallbackBO customerSearchCallbackBO = new CustomerSearchCallbackBO();
        customerSearchCallbackBO.setBosId(bosId);
        customerSearchCallbackBO.setSourceProductInstanceId(productInstanceId);
        customerSearchCallbackBO.setSourceProductId(privateSphere.getProductId());
        customerSearchCallbackBO.setWid(wid);
        customerSearchCallbackBO.setOpenId(externalUserId);
        customerSearchCallbackBO.setNickname(customerResult.getName());
        customerSearchCallbackBO.setGender(customerResult.getGender().getCode());
        customerSearchCallbackBO.setAppId(corpId);
        customerSearchCallbackBO.setExternalUserId(customerResult.getExternalUserid());
        //客户星级
        customerSearchCallbackBO.setCustomerRating(customerResult.getCustomerRatingCode());
        //客户流程阶段
        //赋值流程和阶段ids
        convertProcessStageIds(privateSphere, customerResult.getId(), customerSearchCallbackBO);

        List<String> phoneList = new ArrayList<>();
        if (StringUtils.isNotBlank(customerResult.getMobiles())) {
            phoneList.add(customerResult.getMobiles());
        } else {
            if (StringUtils.isNotBlank(customerResult.getPhone())) {
                phoneList.add(customerResult.getPhone());
            }
        }
        customerSearchCallbackBO.setPhone(phoneList);

        Integer authorizationState = CustomerStatusEnum.UNAUTHORIZED.getCode();
        //查询员工关系
        List<CustomerEmployeeRelation> relationList = new ArrayList<>();
        try {
            relationList = customerServiceProxy.fetchCustomerEmployeeRelation(customerResult.getId(), null, privateSphere, CustomerStatusEnum.DEFAULT, null, null);
        } catch (Exception e) {
            log.error("查询客户好友信息数据出错,error", e);
            return null;
        }

        if (CollectionUtils.isNotEmpty(relationList)) {
            Date latestDate = null;
            Integer friendNum = 0;
            List<CorpWxUserInfoListBean> corpWxUserInfoListBeanList = new ArrayList<>();
            for (CustomerEmployeeRelation customerEmployeeRelation : relationList) {
                CorpWxUserInfoListBean corpWxUserInfoListBean = new CorpWxUserInfoListBean();
                if (latestDate == null) {
                    latestDate = customerEmployeeRelation.getAddTime();
                } else {
                    if (latestDate.before(customerEmployeeRelation.getAddTime())) {
                        latestDate = customerEmployeeRelation.getAddTime();
                    }
                }
                if (null != customerEmployeeRelation.getFriended()) {
                    if (Boolean.TRUE.equals(customerEmployeeRelation.getFriended())) {
                        friendNum++;
                        corpWxUserInfoListBean.setFriended(1);
                    } else {
                        corpWxUserInfoListBean.setFriended(0);
                    }
                }

                ExternalUserAddWayEnum addWayEnum = customerEmployeeRelation.getAddWay();
                if (null != addWayEnum) {
                    corpWxUserInfoListBean.setAddWay(addWayEnum.getCode());
                }
                //二级添加方式
                SubAddWayEnum subAddWay = customerEmployeeRelation.getSubAddWay();
                if (Objects.nonNull(subAddWay)) {
                    corpWxUserInfoListBean.setSubAddWay(Collections.singletonList(subAddWay.getCode()));
                }
                corpWxUserInfoListBean.setUserId(customerEmployeeRelation.getEmployee().getId());
                corpWxUserInfoListBean.setAddTime(customerEmployeeRelation.getAddTime());
                corpWxUserInfoListBeanList.add(corpWxUserInfoListBean);

                if (CustomerStatusEnum.DEFAULT.getCode().equals(customerEmployeeRelation.getStatus().getCode())) {
                    authorizationState = CustomerStatusEnum.DEFAULT.getCode();
                }
            }
            //权限vidList
            customerSearchCallbackBO.setAuthorizeVidList(RelationConvert.mergeVidList(relationList));

            customerSearchCallbackBO.setCorpWxLastAddTime(latestDate);
            if (customerResult.getFirstAddTime() != null) {
                customerSearchCallbackBO.setCorpWxFirstAddTime(customerResult.getFirstAddTime().getTime());
            }
            customerSearchCallbackBO.setCorpWxUserNum(relationList.size());
            customerSearchCallbackBO.setCorpWxFriendNum(friendNum);
            customerSearchCallbackBO.setCorpWxUserInfoList(corpWxUserInfoListBeanList);
        }
        customerSearchCallbackBO.setAuthorizationState(authorizationState);
        return customerSearchCallbackBO;
    }

    // 查客户基础数据
    public CustomerDetailBO getCustomerBaseInfo(CustomerIdGetDTO customerIdGetDTO, PrivateSphere privateSphere) {

        List<CustomerDetailBO> customerBaseInfoList = this.getCustomerBaseInfoList(customerIdGetDTO, privateSphere);
        if (CollectionUtils.isNotEmpty(customerBaseInfoList)) {
            return customerBaseInfoList.get(0);
        }
        return null;
    }

    public List<CustomerDetailBO> getCustomerBaseInfoList(CustomerIdGetDTO customerIdGetDTO, PrivateSphere privateSphereSimple) {

        //校验私域信息
        PrivateSphere privateSphere = privateSphereSimple;
        if (null == privateSphereSimple || StringUtils.isBlank(privateSphereSimple.getCorpId())) {
            BasicInfo basicInfo = customerIdGetDTO.getBasicInfo();
            if (basicInfo == null || basicInfo.getBosId() == null) {
                throw new SoaException(BaseErrorCode.PARMA_EXCPETION.getCode().toString(), BaseErrorCode.PARMA_EXCPETION.getMsg());
            }
            privateSphere = privateSphereThird.fetch(basicInfo, true);

            if (null == privateSphere || StringUtils.isBlank(privateSphere.getCorpId())) {
                return new ArrayList<>();
            }

        }
        String corpId = privateSphere.getCorpId();


        //校验是否传客户id
        if ((StringUtils.isEmpty(customerIdGetDTO.getCustomerId()) && CollectionUtils.isEmpty(customerIdGetDTO.getCustomerIdList()))
                && StringUtils.isEmpty(customerIdGetDTO.getExternalUserId()) && CollectionUtils.isEmpty(customerIdGetDTO.getExternalUserIdList())) {
            throw new SoaException(BaseErrorCode.PARMA_EXCPETION.getCode().toString(), BaseErrorCode.PARMA_EXCPETION.getMsg());
        }

        // 查询客户信息
        List<Customer> customerList = new ArrayList<>();
        try {
            if (CollectionUtils.isNotEmpty(customerIdGetDTO.getCustomerIdList())) {
                customerList = customerServiceProxy.fetchCustomerByIds(customerIdGetDTO.getCustomerIdList(), null, privateSphere, ExternalUserTypeEnum.ALL);
            } else if (CollectionUtils.isNotEmpty(customerIdGetDTO.getExternalUserIdList())) {
                customerList = customerServiceProxy.fetchCustomerByIds(null, customerIdGetDTO.getExternalUserIdList(), privateSphere, ExternalUserTypeEnum.ALL);
            } else if (StringUtils.isNotEmpty(customerIdGetDTO.getCustomerId())) {
                customerList = customerServiceProxy.fetchCustomerByIds(customerIdGetDTO.getCustomerId(), null, privateSphere, ExternalUserTypeEnum.ALL);
            } else if (StringUtils.isNotEmpty(customerIdGetDTO.getExternalUserId())) {
                customerList = customerServiceProxy.fetchCustomerByIds(null, customerIdGetDTO.getExternalUserId(), privateSphere, ExternalUserTypeEnum.ALL);
            }
        } catch (Exception e) {
            log.error("查询客户数据失败,error", e);
        }

        List<CustomerDetailBO> customerDetailBOList = new CopyOnWriteArrayList<>();

        if (CollectionUtils.isNotEmpty(customerList)) {
            CountDownLatch countDownLatch = new CountDownLatch(customerList.size());

            // 多线程赋值并且补充流失状态
            for (Customer customerResp : customerList) {
                queryCustomerThreadPool.submit(() -> {

                    CustomerDetailBO customerDetailBO = new CustomerDetailBO();
                    customerDetailBO.setCustomerId(customerResp.getId());
                    customerDetailBO.setExternalUserId(customerResp.getExternalUserid());
                    if (customerResp.getExternalUserType() != null) {
                        customerDetailBO.setExternalUserType(customerResp.getExternalUserType().getCode());
                    }
                    customerDetailBO.setUnionid(customerResp.getUnionid());
                    customerDetailBO.setNickName(customerResp.getName());
                    customerDetailBO.setAvatar(customerResp.getAvatar());
                    if (customerResp.getGender() != null) {
                        customerDetailBO.setGender(customerResp.getGender().getCode());
                    }
                    customerDetailBO.setPhone(customerResp.getPhone());
                    customerDetailBO.setPosition(customerResp.getPosition());
                    customerDetailBO.setCorpName(customerResp.getCorpName());
                    customerDetailBO.setCorpFullName(customerResp.getCorpFullName());
                    customerDetailBO.setFirstAddTime(customerResp.getFirstAddTime());
                    if (customerResp.getStatus() != null) {
                        customerDetailBO.setStatus(customerResp.getStatus().getCode());
                    }

                    // 判断是否查询流失状态
                    if (customerIdGetDTO.getNeedFlowStatus()) {
                        Long relationCount = customerServiceProxy.fetchCustomerEmployeeRelationCount(corpId, customerResp.getId(), true, CustomerStatusEnum.DEFAULT);

                        // 有数据则未流失
                        if (relationCount > 0) {
                            customerDetailBO.setFlowStatus(false);
                            customerDetailBO.setFriendCount(relationCount.intValue());
                        } else {
                            customerDetailBO.setFlowStatus(true);
                        }
                    }
                    customerDetailBOList.add(customerDetailBO);

                    countDownLatch.countDown();
                });
            }

            try {
                boolean await = countDownLatch.await(2, TimeUnit.SECONDS);
                if (Boolean.FALSE.equals(await)) {
                    log.error("赋值并且补充流失状态超时, param:{}", customerIdGetDTO);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                log.error("InterruptedException e", e);
            } catch (Exception e) {
                log.error("赋值并且补充流失状态失败, param:{},  error:", customerIdGetDTO, e);
            }
        }

        return customerDetailBOList;
    }

    public PageResponse<CustomerDetailBO> getCustomerListByEmployee(CustomerByEmployeeDTO customerByEmployeeDTO) {
        if (StringUtils.isEmpty(customerByEmployeeDTO.getTxUserId())
                && StringUtils.isEmpty(customerByEmployeeDTO.getEmployeeId())) {
            return null;
        }

        //0.根据basicInfo，换取私域
        PrivateSphere privateSphere = privateSphereThird.fetch(customerByEmployeeDTO.getBasicInfo(), true);

        if (StringUtils.isEmpty(customerByEmployeeDTO.getEmployeeId())) {

            Employee employee = employeeProxy.fetchEmployeeById(privateSphere, customerByEmployeeDTO.getTxUserId(), null);

            if (employee != null) {
                customerByEmployeeDTO.setEmployeeId(employee.getId());
            }
        }

        List<CustomerDetailBO> customerDetailBOS = new ArrayList<>();
        MultiResponse<CustomerEmployeeRelation> response = null;
        try {
            response = customerServiceProxy.fetchCustomerEmployeeRelationPage(null, customerByEmployeeDTO.getEmployeeId(), privateSphere,
                    null, CustomerStatusEnum.DEFAULT, true, customerByEmployeeDTO.getPageNum(), customerByEmployeeDTO.getPageSize());
        } catch (Exception e) {
            log.error("通过员工查询客户关系数据数据错误,error",e);
            return new PageResponse<>(customerDetailBOS, customerByEmployeeDTO.getPageNum(), customerByEmployeeDTO.getPageSize(), 0L);
        }

        if (CollectionUtils.isNotEmpty(response.getDataList())) {
            List<String> customerIds = response.getDataList().stream().map(CustomerEmployeeRelation::getCustomerId).collect(Collectors.toList());
            List<Customer> customerList = null;
            try {
                customerList = customerServiceProxy.fetchCustomerByIds(customerIds, null, privateSphere);
            } catch (Exception e) {
                log.error("查询客户数据失败,error", e);
            }

            if (CollectionUtils.isNotEmpty(customerList)) {
                for (Customer customerResp : customerList) {
                    CustomerDetailBO customerDetailBO = new CustomerDetailBO();
                    customerDetailBO.setCustomerId(customerResp.getId());
                    customerDetailBO.setExternalUserId(customerResp.getExternalUserid());
                    customerDetailBO.setUnionid(customerResp.getUnionid());
                    customerDetailBO.setNickName(customerResp.getName());
                    customerDetailBO.setAvatar(customerResp.getAvatar());
                    if (customerResp.getGender() != null) {
                        customerDetailBO.setGender(customerResp.getGender().getCode());
                    }
                    customerDetailBO.setPhone(customerResp.getPhone());
                    customerDetailBO.setPosition(customerResp.getPosition());
                    customerDetailBO.setCorpName(customerResp.getCorpName());
                    customerDetailBO.setCorpFullName(customerResp.getCorpFullName());
                    customerDetailBOS.add(customerDetailBO);
                }
            }
        }


        return new PageResponse<>(customerDetailBOS, response.getPageNum(), response.getPageSize(), (long) response.getTotalPage());
    }

    public PageResponse<ExternalUserListBO> getExternalUserByWids(ExternalUserInfoFindDTO externalUserInfoListDTO) {
        if (externalUserInfoListDTO.getBasicInfo() == null
                || externalUserInfoListDTO.getBasicInfo().getBosId() == null
                || CollectionUtils.isEmpty(externalUserInfoListDTO.getWidList())) {
            return null;
        }

        //0.根据basicInfo，换取私域
        PrivateSphere privateSphere = privateSphereThird.fetch(externalUserInfoListDTO.getBasicInfo(), true);

        // 获取外部联系人基础信息
        List<ExternalUserListBO> externalUserInfoByWids = this.getExternalUserInfoByWids(privateSphere, externalUserInfoListDTO.getWidList(), externalUserInfoListDTO.getStatus(), false);

        // 获取流失状态
        if (CollectionUtils.isNotEmpty(externalUserInfoByWids) && (!externalUserInfoListDTO.getSimpleFetch())) {
            for (ExternalUserListBO externalUserListBO : externalUserInfoByWids) {

                List<CustomerEmployeeRelation> relationList = new ArrayList<>();
                try {
                    relationList = customerServiceProxy.fetchCustomerEmployeeRelation(externalUserListBO.getCustomerId(), null, privateSphere, CustomerStatusEnum.DEFAULT, true, null);
                } catch (Exception e) {
                    log.error("查询客户员工关系数据错误,error", e);
                }

                externalUserListBO.setFriendCount(relationList.size());
                // 有数据则未流失
                if (CollectionUtils.isNotEmpty(relationList)) {
                    externalUserListBO.setFlowStatus(false);
                } else {
                    externalUserListBO.setFlowStatus(true);
                }

            }
        }

        PageResponse<ExternalUserListBO> pageResponse = new PageResponse<>(externalUserInfoByWids,
                externalUserInfoListDTO.getPageNum(), externalUserInfoListDTO.getPageSize(), (long) externalUserInfoByWids.size());
        return pageResponse;
    }

    public Boolean triggerSyncCustomer(SyncCustomerTriggerDTO syncCustomerTriggerDTO) {
        // 查询私域
        BasicInfo basicInfo = new BasicInfo();
        basicInfo.setCorpId(syncCustomerTriggerDTO.getCorpId());
        basicInfo.setBosId(syncCustomerTriggerDTO.getBosId());
        PrivateSphere privateSphere = privateSphereThird.fetch(basicInfo, false);
        // 迁移中 禁用同步
        Long bosId = privateSphere.getBosId();
        BatchMigrationStatusRequest batchMigrationStatusRequest = new BatchMigrationStatusRequest();
        batchMigrationStatusRequest.setBosId(Lists.newArrayList(bosId));
        List<BatchMigrationStatusVo> batchMigrationStatus = SoaUtil.unpack(ecAdapterService.batchMigrationStatus(batchMigrationStatusRequest));
        if (CollectionUtils.isNotEmpty(batchMigrationStatus)) {
            // 1: 迁移中
            if (batchMigrationStatus.get(0).getStatus() != null && batchMigrationStatus.get(0).getStatus().equals(1)) {
                log.info("数据迁移中禁用同步 request: {}", JSON.toJSONString(syncCustomerTriggerDTO));
                return false;
            }
        }


        // 判断自动同步时间间隔  自动手动相互不影响
        if (!syncCustomerTriggerDTO.getManualFlag()) {
            Boolean flag = redisService.setNX(RedisKeyConstant.getAutoSyncExternaluserKey(String.valueOf(syncCustomerTriggerDTO.getBosId())), String.valueOf(System.currentTimeMillis()), autoSyncDefaultTime, TimeUnit.MINUTES);
            if (!flag) {
                log.info("自动触发历史外部联系人同步失败 request:{} 间隔时间为{}分钟 上次自动同步时间戳为{}",
                        JSON.toJSONString(syncCustomerTriggerDTO), autoSyncDefaultTime, redisService.get(RedisKeyConstant.getAutoSyncExternaluserKey(String.valueOf(privateSphere.getBosId()))));
//                this.updateCustomerDataProgress(syncCustomerTriggerDTO.getAuthRangeRecordUid(), CustomDataTransferEnum.LIMIT_IN_24H);
                return false;
            }
        }

        ExternalContactSyncDTO externalContactSyncDTO = new ExternalContactSyncDTO();
        externalContactSyncDTO.setCorpId(syncCustomerTriggerDTO.getCorpId());
        //默认给个suiteId
        PrivateSphere privateSphereSearch = new PrivateSphere();
        privateSphereSearch.setCorpId(syncCustomerTriggerDTO.getCorpId());
        privateSphereSearch.setBosId(bosId);
        privateSphereSearch.setProductId(aewcProductId);

        if (StringUtils.isBlank(syncCustomerTriggerDTO.getSuiteId())) {
            SoaResponse<PrivateSphere, Void> soaResponse =
                    privateSphereService.fetch(privateSphereSearch);
            if (soaResponse != null && soaResponse.getResponseVo() != null) {
                externalContactSyncDTO.setSuiteId(soaResponse.getResponseVo().getSuiteId());
                externalContactSyncDTO.setTemplateId(soaResponse.getResponseVo().getTemplateId());
            }
        } else {
            externalContactSyncDTO.setSuiteId(syncCustomerTriggerDTO.getSuiteId());
            SoaResponse<PrivateSphere, Void> soaResponse = privateSphereService.fetch(privateSphereSearch);
            if (soaResponse != null && soaResponse.getResponseVo() != null) {
                externalContactSyncDTO.setTemplateId(soaResponse.getResponseVo().getTemplateId());
            }
        }

        log.info("通知渠道进行历史外部联系人同步 request: {}", JSON.toJSONString(externalContactSyncDTO));
        SoaResponse<Long, Void> soaResponse =
                channelAdapterService.syncCorpWxAllExternalContact(externalContactSyncDTO);
        if (soaResponse == null || soaResponse.getResponseVo() == null) {
//            this.updateCustomerDataProgress(syncCustomerTriggerDTO.getAuthRangeRecordUid(), CustomDataTransferEnum.DATA_TRANSFER_FAIL);
            log.error("triggerSyncCustomer syncCorpWxAllExternalContact error, param:{}", JSON.toJSONString(syncCustomerTriggerDTO));
        }
//        else {
//            this.updateCustomerDataProgress(syncCustomerTriggerDTO.getAuthRangeRecordUid(), CustomDataTransferEnum.CALL_INTERFACE_SUCCESS);
//        }
        // 异步初始化客户群数据
        customerGroupInitialThreadPool.execute(() ->
                chatGroupFacade.initChatGroupData(syncCustomerTriggerDTO.getCorpId(), syncCustomerTriggerDTO.getBosId())
        );
        //同步客户群统计数据
//        statisticThreadPool.execute(() -> {
//            StatisticsRequestInfo statisticsRequestInfo = new StatisticsRequestInfo();
//            statisticsRequestInfo.setPrivateSphere(privateSphereSearch);
//            statisticsService.initChatGroupStatistic(statisticsRequestInfo);
//        });

        customerGroupInitialThreadPool.execute(() -> {
            //同步标签数据
            try {
                String loseKey = String.format(RedisLockConstant.INIT_TAG, syncCustomerTriggerDTO.getCorpId());
                boolean initFlag = redisService.setNXNew(loseKey, "", tagInitInterval, TimeUnit.SECONDS);

                if (initFlag) {
                    //初始化标签
                    log.info("初始化历史标签, corpId:{}", syncCustomerTriggerDTO.getCorpId());
                    tagManageService.initTag(privateSphere, true);
                }

            } catch (Exception e) {
                log.error("外部联系人消息, 初始化标签组/标签失败, corpId:{}, error:", syncCustomerTriggerDTO.getCorpId(), e);
            }
        });


        return Boolean.TRUE;
    }


    public Boolean updateCustomerRemark(CustomerRemarkDTO customerRemarkDTO) {

        if (StringUtils.isBlank(customerRemarkDTO.getCustomerId())) {
            throw new BizException("customerId 不能为空");
        }
        if (StringUtils.isBlank(customerRemarkDTO.getEmployeeId())) {
            throw new BizException("employeeId 不能为空");
        }
        if (StringUtils.isBlank(customerRemarkDTO.getRemark())) {
            throw new BizException("remark 不能为空");
        }

        PrivateSphere privateSphere = privateSphereThird.fetch(customerRemarkDTO.getBasicInfo(), false);
        List<Customer> customerList = null;
        try {
            customerList = customerServiceProxy.fetchCustomerByIds(customerRemarkDTO.getCustomerId(), null, privateSphere);
        } catch (Exception e) {
            throw new BizException("客户信息不存在");
        }

        if (CollectionUtils.isEmpty(customerList)) {
            throw new BizException("客户信息不存在");
        }

        Employee employee = employeeProxy.fetchEmployeeById(privateSphere, null, customerRemarkDTO.getEmployeeId());

        if (employee == null) {
            throw new BizException("员工信息不存在");
        }

        ExternalRemarkUpdateDTO externalRemarkUpdateDTO = new ExternalRemarkUpdateDTO();
        externalRemarkUpdateDTO.setCorpId(customerList.get(0).getCorpId());
        externalRemarkUpdateDTO.setProviderIdentity(privateSphere.getChannelProviderIdentity());
        externalRemarkUpdateDTO.setUserid(employee.getTxUserId());
        externalRemarkUpdateDTO.setExternalUserId(customerList.get(0).getExternalUserid());
        externalRemarkUpdateDTO.setRemark(customerRemarkDTO.getRemark());
        if (PrivateSphereEncryptCorpEnum.CIPHER.getCode().equals(privateSphere.getEncryptCorpId())) {
            externalRemarkUpdateDTO.setTemplateId(privateSphere.getTemplateId());
            externalRemarkUpdateDTO.setType(WechatWorkAppType.PROXIED_INTERNAL_APP.getType());

        } else {
            externalRemarkUpdateDTO.setType(WechatWorkAppType.CONTACT.getType());
        }
        SoaResponse<WxResponseBaseDTO, Void> response = channelAdapterService.updateExternalRemark(externalRemarkUpdateDTO);
        if (!SoaResponseUtil.isSuccNotNull(response)) {
            return SoaUtil.unpack(SoaResponseUtil.ok(Boolean.TRUE));
        } else {
            return SoaUtil.unpack(SoaResponseUtil.ok(Boolean.FALSE));
        }
    }

    public Boolean exportExternalUserList(ExternalUserInfoFindDTO externalUserInfoFindDTO) {
        BasicInfo basicInfo = externalUserInfoFindDTO.getBasicInfo();
        PrivateSphere privateSphereResult = privateSphereThird.fetch(basicInfo, Boolean.TRUE);
        //step 1 查看当前bos_id+wid是否在30秒内已经导出过了
        Boolean checkExport = checkExport(externalUserInfoFindDTO);
        if (!checkExport) {
            //抛出异常
            throw new BizException(BaseErrorCode.USER_EXPORT_SUBMIT_TIME.getCode(), BaseErrorCode.USER_EXPORT_SUBMIT_TIME.getMsg());
        }

        Integer taskType = WosExporterEnum.EX_USER_EXPORTER.getBizType();
        //step 针对企微版本导出配置
        if (exportProductVersionList.contains(privateSphereResult.getProductVersionId())) {
            //判断是否有商城
            Map<Long, List<ProductInstanceDTO>> productByBosId =
                    findProductByBosId(privateSphereResult.getBosId(), Lists.newArrayList(Long.valueOf(mallProductId)));
            List<ProductInstanceDTO> productInstanceDTOS = productByBosId.get(Long.valueOf(mallProductId));
            if (CollectionUtils.isNotEmpty(productInstanceDTOS)) {
                //说明有商城
                taskType = ExportTaskTypeEnum.CUSTOMER_MALL_INFO_DOWNLOAD.getType();
            }
        }

        //step 3 创建导出任务
        ExportTaskSaveDTO exportTaskSaveDTO = new ExportTaskSaveDTO();
        exportTaskSaveDTO.setBosId(privateSphereResult.getBosId());
        exportTaskSaveDTO.setWid(externalUserInfoFindDTO.getMerchantWid());
        exportTaskSaveDTO.setFileName(WosExporterEnum.EX_USER_EXPORTER.getFileName() + "-" + DateUtils.getTodayDate());
        exportTaskSaveDTO.setTaskType(taskType);
        exportTaskSaveDTO.setVid(basicInfo.getVid());
        exportTaskSaveDTO.setProductId(privateSphereResult.getProductId());
        exportTaskSaveDTO.setParams(JsonUtil.obj2Str(ExporterConvert.convertToExporterDTO(externalUserInfoFindDTO)));
        SoaResponse<ExportTaskSaveVo, Void> exportTaskSaveVoVoidSoaResponse = exportService.saveExportTask(exportTaskSaveDTO);
        if (!SoaResponseUtil.isSuccNotNull(exportTaskSaveVoVoidSoaResponse)) {
            throw new BizException(Long.valueOf(exportTaskSaveVoVoidSoaResponse.getReturnCode()), exportTaskSaveVoVoidSoaResponse.getReturnMsg());
        }
        return Boolean.TRUE;
    }

    /**
     * 查询商品信息
     *
     * @param bosId
     * @param productIds
     * @return
     */
    protected Map<Long, List<ProductInstanceDTO>> findProductByBosId(Long bosId, List<Long> productIds) {
        // 查根节点开通的产品
        QueryProductInstanceOfRootVidRequest queryProductInstanceOfRootVidRequest = new QueryProductInstanceOfRootVidRequest();
        queryProductInstanceOfRootVidRequest.setBosId(bosId);
        queryProductInstanceOfRootVidRequest.setProductIdList(productIds);
        List<ProductInstanceDTO> productInstanceDTOS = SoaUtil.unpack(bosAdapterService.queryProductInstanceOfRootVid(queryProductInstanceOfRootVidRequest));

        Map<Long, List<ProductInstanceDTO>> resultMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(productInstanceDTOS)) {
            for (ProductInstanceDTO productInstanceDTO : productInstanceDTOS) {
                List<ProductInstanceDTO> resultList = resultMap.get(productInstanceDTO.getProductId());
                if (resultList == null) {
                    resultList = new ArrayList<>();
                    resultList.add(productInstanceDTO);
                    resultMap.put(productInstanceDTO.getProductId(), resultList);
                } else {
                    resultList.add(productInstanceDTO);
                }
            }
        }

        return resultMap;
    }

    /**
     * 判断当前bosID+wid 30秒内是否创建过导出任务
     *
     * @param externalUserInfoFindDTO
     * @return
     */
    private Boolean checkExport(ExternalUserInfoFindDTO externalUserInfoFindDTO) {
        Long merchantWid = externalUserInfoFindDTO.getMerchantWid();
        Long bosId = externalUserInfoFindDTO.getBasicInfo().getBosId();
        String redisKey = ExportConstants.USER_EXPORT_SAVE_PRE + bosId + ":" + merchantWid;
        return redisService.setNXAndExpire(redisKey, NumberUtils.LONG_ONE.toString(), ExportConstants.MAX_EXPIRE_TIME, TimeUnit.SECONDS);
    }



    /**
     * 通过ES获取列表或导出的外部联系人
     *
     * @param privateSphere
     * @param externalUserInfoFindDTO
     * @return
     */
    private PageResponse<ExternalUserListBO> searchExternalUserList(PrivateSphere privateSphere, ExternalUserInfoFindDTO externalUserInfoFindDTO) {

        //2、根据入参条件进行搜索
        BaseAuthReqDTO<CustomerSearchDTO> baseAuthReqDTO = new BaseAuthReqDTO<>();
        List<ExternalUserListBO> resultList = Lists.newArrayList();


        CustomerSearchBO customerSearchBO;
        do {
            externalUserInfoFindDTO.setPageNum(externalUserInfoFindDTO.getPageNum());
            externalUserInfoFindDTO.setPageSize(externalUserInfoFindDTO.getPageSize());
            CustomerSearchDTO customerSearchDTO = CustomerRequestBuild.buildOneCrmSearchRequest(privateSphere.getCorpId(), externalUserInfoFindDTO);
            baseAuthReqDTO.setRequest(customerSearchDTO);


            customerSearchBO = SoaUtil.unpack(oneCrmAdapterService.searchUserInfoByPage(baseAuthReqDTO));

            List<ExternalUserBO> externalUserList = customerSearchBO.getExternalUserList();

            if (CollectionUtils.isNotEmpty(externalUserList)) {
                //过滤externalUserId为null的场景
                externalUserList = externalUserList.stream().filter(item -> Objects.nonNull(item.getExternalUserId())).collect(Collectors.toList());
                customerSearchBO.setExternalUserList(externalUserList);
                //externalUserList存在wid未合并的数据，换成新的wid对象
                Set<Long> delWidSet = analyseRepeatExternalUserId(externalUserList, privateSphere);
                if (CollectionUtils.isNotEmpty(delWidSet)) {
                    //移除externalUserId对应多个wid的数据
                    externalUserList = externalUserList.stream().filter(item -> delWidSet.contains(item.getWid())).collect(Collectors.toList());
                    customerSearchBO.setExternalUserList(externalUserList);

                    //发送删除消息
                    sendDelCustomerMsg(delWidSet, privateSphere);
                }

                List<ExternalUserListBO> externalUserListBOS = buildExternalUserListBOList(privateSphere, customerSearchBO);
                resultList.addAll(externalUserListBOS);
            }


            if (externalUserInfoFindDTO.getSearchAllUser() != null && externalUserInfoFindDTO.getSearchAllUser()) {
                //查询所有用户
                externalUserInfoFindDTO.setPageNum(externalUserInfoFindDTO.getPageNum() + 1);
            }


            //上游传查询所有用户标识是查所有用户 并且 可以一直查到wid 则一直循环
        } while (externalUserInfoFindDTO.getSearchAllUser() != null && externalUserInfoFindDTO.getSearchAllUser()
                && customerSearchBO.getExternalUserList() != null && externalUserInfoFindDTO.getPageSize().equals(customerSearchBO.getExternalUserList().size()));


        PageResponse<ExternalUserListBO> response = new PageResponse<>();
        response.setResults(resultList);
        response.setTotalCount(customerSearchBO.getTotalCount());
        return response;
    }


    /**
     * 删除重复externalUserId对应多个wid的数据
     *
     * @param externalUserList externalUserList
     * @param privateSphere    privateSphere
     */
    public Set<Long> analyseRepeatExternalUserId(List<ExternalUserBO> externalUserList, PrivateSphere privateSphere) {
        if (CollectionUtils.isEmpty(externalUserList)) {
            return new HashSet<>();
        }
        //找到重复的externalUserId
        Map<String, List<ExternalUserBO>> map = externalUserList.stream().filter(item -> Objects.nonNull(item.getExternalUserId()))
                .collect(Collectors.groupingBy(ExternalUserBO::getExternalUserId));

        Set<Long> removeWidList = new HashSet<>();
        map.forEach((externalUserId, list) -> {
            //找到重复的
            if (CollectionUtils.isNotEmpty(list) && list.size() > 1) {
                //换取此externalUserId对应的wid
                Long superWid = customerThird.getSuperWid(privateSphere.getBosId(),
                        externalUserId, privateSphere.getCorpId());
                if (Objects.nonNull(superWid)) {
                    for (ExternalUserBO externalUserBO : list) {
                        Long wid = externalUserBO.getWid();
                        //取到和passport对应的wid不一致的 wid数据
                        if (!superWid.equals(wid)) {
                            removeWidList.add(wid);
                        }
                    }
                }
            }
        });
        return removeWidList;
    }

    private void sendDelCustomerMsg(Set<Long> delWidSet, PrivateSphere privateSphere) {
        if (CollectionUtils.isEmpty(delWidSet)) {
            return;
        }
        for (Long wid : delWidSet) {
            CustomerSearchInitEventMsg customerSearchMsg = new CustomerSearchInitEventMsg();
            customerSearchMsg.setBosId(privateSphere.getBosId());
            customerSearchMsg.setSourceProductInstanceId(privateSphere.getProductInstanceId());
            customerSearchMsg.setSourceProductId(privateSphere.getProductId());
            customerSearchMsg.setDeleted(Boolean.TRUE);
            customerSearchMsg.setWid(wid);
            ArtemisBaseInfo<CustomerSearchInitEventMsg> artemisBaseInfo = new ArtemisBaseInfo<>();
            artemisBaseInfo.setTopic(ArtemisConstant.Topic.CORE_EXTERNALUSER_INIT_EVENT);
            artemisBaseInfo.setEvent(customerSearchMsg);
            artemisBaseInfo.setProducer(ArtemisConstant.USER);
            log.info("删除重复externalUserId的数据，推送到搜索服务消息, request:{}", JSON.toJSONString(artemisBaseInfo));
            artemisService.sendToArtemis(artemisBaseInfo,privateSphere.getBosId());
        }
    }


    private List<ExternalUserListBO> buildExternalUserListBOList(PrivateSphere privateSphere, CustomerSearchBO customerSearchBO) {
        List<ExternalUserBO> externalUserList = customerSearchBO.getExternalUserList();
        if (CollectionUtils.isEmpty(externalUserList)) {
            return new ArrayList<>();
        }

        Map<String, Long> externalUserIdAndWidMap = CustomerConvert.toExternalUserIdAndWidMap(externalUserList);
        List<String> externalUserIdList = CustomerConvert.toExternalUserIdList(externalUserList);


        List<ExternalUserListBO> externalUserListBOS = new ArrayList<>();

        List<List<String>> customerPartition = Lists.partition(externalUserIdList, externalUserIdPartitionCount);
        for (List<String> externalUserIds : customerPartition) {

            //根据externalUserId 去企微助手获取customer
            List<Customer> customerResponses;
            try {
                customerResponses = customerServiceProxy.fetchCustomerByIds(null, externalUserIds, privateSphere, Boolean.TRUE);
            } catch (Exception e) {
                log.error("根据externalUserId 去企微助手获取customer异常, externalUserIds:{}", JSON.toJSONString(externalUserIds), e);
                continue;
            }

            for (Customer customerResponse : customerResponses) {
                ExternalUserListBO externalUserInfoBO = new ExternalUserListBO();
                externalUserInfoBO.setCorpId(privateSphere.getCorpId());
                externalUserInfoBO.setCustomerId(customerResponse.getId());
                if (customerResponse.getExternalUserType() != null) {
                    externalUserInfoBO.setExternalUserType(customerResponse.getExternalUserType().getCode());
                }
                externalUserInfoBO.setExternalUserWid(externalUserIdAndWidMap.get(customerResponse.getExternalUserid()));
                externalUserInfoBO.setExternalUserId(customerResponse.getExternalUserid());
                externalUserInfoBO.setUnionid(customerResponse.getUnionid());
                externalUserInfoBO.setPhone(customerResponse.getPhone());
                externalUserInfoBO.setExternalUserName(customerResponse.getName());
                externalUserInfoBO.setGender(customerResponse.getGender().getCode());
                externalUserInfoBO.setAvatar(customerResponse.getAvatar());
                externalUserInfoBO.setFirstAddTime(customerResponse.getFirstAddTime());
                // customer_detail的手机号
                externalUserInfoBO.setMobiles(customerResponse.getMobiles());
                //客户星级
                externalUserInfoBO.setCustomerRating(customerResponse.getCustomerRatingCode());
                WechatworkChannelEnum channel;
                if ((channel = customerResponse.getChannel()) != null) {
                    WechatWorkChannelDescEnum enumByValue = WechatWorkChannelDescEnum.getEnumByValue(channel.getCode());
                    externalUserInfoBO.setOtherChannel(enumByValue.getDesc());
                }
                if (customerResponse.getStatus() != null) {
                    externalUserInfoBO.setStatus(customerResponse.getStatus().getCode());
                }

                externalUserListBOS.add(externalUserInfoBO);
            }
        }

        //按照externalUserIdList重新排序
        return sortCustomerByParam(externalUserListBOS, externalUserIdList);
    }

    /**
     * 按照externalUserIds的顺序排序externalUserInfo
     *
     * @param externalUserInfo externalUserInfo
     * @param externalUserIds  externalUserIdList
     * @return
     */
    private List<ExternalUserListBO> sortCustomerByParam(List<ExternalUserListBO> externalUserInfo, List<String> externalUserIds) {
        List<ExternalUserListBO> sortedList = new ArrayList<>();

        Map<String, ExternalUserListBO> map = externalUserInfo.stream().collect(Collectors.toMap(ExternalUserListBO::getExternalUserId, Function.identity(), (k1, k2) -> k1));
        externalUserIds.forEach(item -> {

            ExternalUserListBO bo = map.get(item);
            if (Objects.nonNull(bo)) {
                sortedList.add(bo);
            }
        });

        return sortedList;
    }

    public Boolean saveCustomerCDPDetail(CustomerCDPInfoSaveDTO customerCDPInfoSaveDTO) {
        //0. 根据basicInfo，查询私域信息
        PrivateSphere privateSphere = privateSphereThird.fetch(customerCDPInfoSaveDTO.getBasicInfo(), true);
        if (StringUtils.isEmpty(customerCDPInfoSaveDTO.getCustomerId()) || StringUtils.isEmpty(privateSphere.getCorpId())) {
            return false;
        }

        // 1. 查询原始客户信息 后续区分跟进事件
        Customer customer = customerServiceProxy.fetchCustomer(customerCDPInfoSaveDTO.getCustomerId(), customerCDPInfoSaveDTO.getExternalUserId(), privateSphere);
        if (customer == null) {
            return false;
        }

        // 2. 保存到customerDetail
        Customer saveCustomer = new Customer();
        saveCustomer.setCorpId(privateSphere.getCorpId());
        saveCustomer.setId(customerCDPInfoSaveDTO.getCustomerId());
        saveCustomer.setMobiles(customerCDPInfoSaveDTO.getMobiles());
        saveCustomer.setBirthday(customerCDPInfoSaveDTO.getBirthday());
        saveCustomer.setQq(customerCDPInfoSaveDTO.getQq());
        //客户星级字段赋值
        Integer newCustomerRating = customerCDPInfoSaveDTO.getCustomerRating();
        String newRatingDesc = CustomerRatingEnum.getDescByCode(newCustomerRating);
        saveCustomer.setCustomerRating(CustomerRatingEnum.getEnumByCode(newCustomerRating));
        Address address = new Address();
        address.setProvinceName(customerCDPInfoSaveDTO.getProvince());
        address.setCityName(customerCDPInfoSaveDTO.getCity());
        address.setDistrictName(customerCDPInfoSaveDTO.getDistrict());
        address.setAddress(customerCDPInfoSaveDTO.getAddress());
        saveCustomer.setAddress(address);
        SoaUtil.unpack(customerService.updateCustomerDeatil(saveCustomer));
        //fixme 为啥存两份
//        if(StringUtils.isNotBlank(customerCDPInfoSaveDTO.getMobiles())){
//            saveCustomer.setPhone(customerCDPInfoSaveDTO.getMobiles());
//            saveCustomer.setExternalUserid(customer.getExternalUserid());
//            customerService.updateCustomer(saveCustomer);
//        }

        //需要通知客搜，手机号可能发生了变更
        Long superWid = customerThird.getSuperWid(privateSphere.getBosId(),
                customer.getExternalUserid(), privateSphere.getCorpId());
        addCorpExternaluserSecondHandler.updateCustomerSearchMsg(superWid, privateSphere.getBosId(),
                privateSphere.getProductInstanceId(), privateSphere.getProductId());

        // 3. 保存到跟进记录ActionLog
        Employee employee = employeeProxy.fetchEmployeeById(privateSphere, customerCDPInfoSaveDTO.getUserId(), null);
        if (employee == null) {
            throw new BizException("未查到指定员工");
        }
        this.addActionLog(newRatingDesc, null,
                ActionLogEventTypeEnum.CUSTOMER_RATING, ActionLogEventTypeEnum.CUSTOMER_RATING, customer.getId(),
                employee.getId(), privateSphere);
        this.addActionLog(customerCDPInfoSaveDTO.getMobiles(), customer.getMobiles(),
                ActionLogEventTypeEnum.ADD_MOBILES, ActionLogEventTypeEnum.UPDATE_MOBILES, customer.getId(),
                employee.getId(), privateSphere);
        this.addActionLog(customerCDPInfoSaveDTO.getBirthday(), customer.getBirthday(),
                ActionLogEventTypeEnum.ADD_BIRTHDAY, ActionLogEventTypeEnum.UPDATE_BIRTHDAY, customer.getId(),
                employee.getId(), privateSphere);
        this.addActionLog(customerCDPInfoSaveDTO.getQq(), customer.getQq(),
                ActionLogEventTypeEnum.ADD_QQ, ActionLogEventTypeEnum.UPDATE_QQ, customer.getId(),
                employee.getId(), privateSphere);
        this.addActionLog(customerCDPInfoSaveDTO.getAddress(), customer.getAddress() != null ? customer.getAddress().getAddress() : "",
                ActionLogEventTypeEnum.ADD_ADDRESS, ActionLogEventTypeEnum.UPDATE_ADDRESS, customer.getId(),
                employee.getId(), privateSphere);
        String oldAddressStr = "";
        if (customer.getAddress() != null) {
            Address oldaddress = customer.getAddress();
            if (StringUtils.isNotEmpty(customer.getAddress().getProvinceName())) {
                oldAddressStr = oldaddress.getProvinceName() + " " + oldaddress.getCityName() + " " + oldaddress.getDistrictName();
            }
        }
        String newAddressStr = "";
        if (StringUtils.isNotEmpty(customerCDPInfoSaveDTO.getProvince())) {
            newAddressStr = customerCDPInfoSaveDTO.getProvince() + " " + customerCDPInfoSaveDTO.getCity() + " " + customerCDPInfoSaveDTO.getDistrict();
        }
        this.addActionLog(newAddressStr, oldAddressStr,
                ActionLogEventTypeEnum.ADD_DIVISION, ActionLogEventTypeEnum.UPDATE_DIVISION, customer.getId(),
                employee.getId(), privateSphere);

        // 4. 推送CDP打点
        Long wid = customerThird.getSuperWid(privateSphere.getBosId(), customer.getExternalUserid(), privateSphere.getCorpId());

        CDPUserMarkDTO cdpUserMarkDTO = new CDPUserMarkDTO();
        cdpUserMarkDTO.setuKey(String.valueOf(wid));
        cdpUserMarkDTO.setuKeyType("wid");
        cdpUserMarkDTO.setsChannelType(203);
        cdpUserMarkDTO.setsChannelId(privateSphere.getProductInstanceId());
        cdpUserMarkDTO.setBosId(privateSphere.getBosId());
        cdpUserMarkDTO.setUpdateTime(String.valueOf(System.currentTimeMillis()));
        //todo @see com.weimob.mcloud.wechatwork.customer.domain.CdpDataJsonInfo
        Map<String, Object> dataJson = new HashMap<>();
        dataJson.put("productInstanceId", privateSphere.getProductInstanceId());
        dataJson.put("wid", String.valueOf(wid));
        dataJson.put("externalUserId", customerCDPInfoSaveDTO.getExternalUserId());
        dataJson.put("corpId", privateSphere.getCorpId());
        dataJson.put("timestamp", new Date().getTime());
        dataJson.put("phone", saveCustomer.getMobiles());
        dataJson.put("qq", saveCustomer.getQq());
        dataJson.put("address", saveCustomer.getAddress());
        dataJson.put("birthday", saveCustomer.getBirthday());
        //打点数据 直辖市province数据不能带"市" 如：province：上海 city：上海市
        dataJson.put("province", address.getProvinceName());
        dataJson.put("city", address.getCityName());
        dataJson.put("area", address.getDistrictName());

        cdpUserMarkDTO.setDataJson(dataJson);
        cdpUserMarkDTO.setCdpMarkTypeEnum(CDPMarkTypeEnum.CDP_USER_ATTRIBUTE);
        cdpUserMarkDTO.setCdpMarkMessageEventEnum(com.weimob.mcloud.wechatwork.core.adapter.enums.cdp.CdpMarkMessageEventEnum.CUSTOMER_ATTRIBUTE);
        cdpUserAdapterService.markCDPUserMsg(cdpUserMarkDTO);
        log.info("客户打点事件 markCDPUserMsg message:{}", cdpUserMarkDTO);

        return true;
    }

    public void addActionLog(String newValue, String oldValue,
                             ActionLogEventTypeEnum addEnum, ActionLogEventTypeEnum updateEnum,
                             String customerId, String employeeId, PrivateSphere privateSphere) {
        if (StringUtils.equals(newValue, oldValue)) {
            return;
        }
        CorpActionLogInsertDTO corpActionLogInsertDTO = new CorpActionLogInsertDTO();
        BasicInfo basicInfo = new BasicInfo();
        BeanUtils.copyProperties(privateSphere, basicInfo);
        corpActionLogInsertDTO.setBasicInfo(basicInfo);

        corpActionLogInsertDTO.setCorpid(privateSphere.getCorpId());
        corpActionLogInsertDTO.setBizType(ActionLogBizeTypeEnum.TRACK_RECORD.getCode());
        corpActionLogInsertDTO.setOrgUserId(employeeId);
        corpActionLogInsertDTO.setCustomerId(customerId);
        corpActionLogInsertDTO.setActionTime(new Date());
        if (StringUtils.isBlank(oldValue)) {
            if (StringUtils.isNotBlank(newValue)) {
                corpActionLogInsertDTO.setActionValue(newValue);
                corpActionLogInsertDTO.setActionDesc(String.format(addEnum.getDesc(), newValue));
                corpActionLogInsertDTO.setEventType(addEnum.getCode());
                this.addActionLog(corpActionLogInsertDTO);
            }
        } else {
            if (StringUtils.isNotBlank(newValue) && !oldValue.equals(newValue)) {
                corpActionLogInsertDTO.setActionValue(newValue);
                corpActionLogInsertDTO.setActionDesc(String.format(updateEnum.getDesc(), oldValue, newValue));
                corpActionLogInsertDTO.setEventType(updateEnum.getCode());
                this.addActionLog(corpActionLogInsertDTO);
            }
        }
    }

    private List<TagDetailBO> toTagDetailBO(List<TagBO> tagBOList) {

        List<TagDetailBO> tagDetailBOS = new ArrayList<>();
        for (TagBO tagBO : tagBOList) {
            TagDetailBO tagDetailBO = toTagDetailBO(tagBO);
            tagDetailBOS.add(tagDetailBO);
        }

        return tagDetailBOS;
    }

    private TagDetailBO toTagDetailBO(TagBO tagBO) {
        TagGroupBO tagGroupBO = tagBO.getTagGroupBO();

        TagDetailBO tagDetailBO = new TagDetailBO();
        tagDetailBO.setCdpTagGroupId(tagGroupBO.getCdpTagGroupId());
        tagDetailBO.setCdpTagId(tagBO.getCdpTagId());
        tagDetailBO.setTagGroupName(tagGroupBO.getTagGroupName());
        tagDetailBO.setTagName(tagBO.getTagName());
        tagDetailBO.setTagSource(tagBO.getTagSource());

        return tagDetailBO;
    }

//    private Long getWid(Long bosId, String externalUserId, String corpId) {
//        if (StringUtils.isBlank(externalUserId) || Objects.isNull(bosId) || StringUtils.isBlank(corpId)) {
//            return null;
//        }
//
//        //1、获取外部联系人wid
//        AccountGetDTO accountGetDTO = new AccountGetDTO();
//        accountGetDTO.setBosId(bosId);
//        accountGetDTO.setOpenId(externalUserId);
//        accountGetDTO.setUcSourceTypeEnum(UCSourceTypeEnum.WORK_WEIXIN_EXTERNAL_USERID);
//        accountGetDTO.setAppId(corpId);
//
//        AccountGetBO userChannelInfoDTO = SoaUtil.unpack(oneCrmAdapterService.getAccountByOpenId(accountGetDTO));
//        if (Objects.isNull(userChannelInfoDTO)) {
//            return null;
//        }
//
//        return userChannelInfoDTO.getWid();
//
//    }

    /**
     * 查询外部联系人账户信息
     *
     * @param bosId
     * @param wid
     * @return
     */
    private AccountBO queryAccountBO(Long bosId, Long productInstanceId, Long wid, String tcode) {

        //查询客户账户余额
        CDPUserAccountGetDTO cdpUserAccountGetDTO = new CDPUserAccountGetDTO();
        cdpUserAccountGetDTO.setBosId(bosId);
        cdpUserAccountGetDTO.setWid(wid);
        SoaResponse<CustomerBalanceBO, ?> customerBalanceBOSoaResponse =
                cdpUserAdapterService.queryCustomerBalance(cdpUserAccountGetDTO);
        CustomerBalanceBO customerBalanceBO = SoaUtil.unpack(customerBalanceBOSoaResponse);


        SoaResponse<CustomerPointBO, ?> customerPointBOSoaResponse =
                cdpUserAdapterService.queryCustomerPoint(cdpUserAccountGetDTO);
        CustomerPointBO customerPointBO = SoaUtil.unpack(customerPointBOSoaResponse);

        MemberInfoQueryDTO memberInfoQueryDTO = new MemberInfoQueryDTO();
        memberInfoQueryDTO.setBosId(bosId);
        memberInfoQueryDTO.setProductInstanceId(productInstanceId);
        memberInfoQueryDTO.setWid(wid);
        memberInfoQueryDTO.setTcode(tcode);
        SoaResponse<CouponNumBO, ?> couponNumBOSoaResponse = cdpUserAdapterService.queryCustomerCouponNum(memberInfoQueryDTO);

        CouponNumBO couponNumBO = SoaUtil.unpack(couponNumBOSoaResponse);

        // 账户余额
        AccountBO accountBO = new AccountBO();
        if (Objects.nonNull(customerBalanceBO)) {
            BigDecimal totalAmount = customerBalanceBO.getTotalAmount();
            if (Objects.nonNull(totalAmount)) {
                accountBO.setAccountBalances(totalAmount.doubleValue());
            } else {
                accountBO.setAccountBalances(0.0);
            }

        } else {
            accountBO.setAccountBalances(0.0);
        }

        // 积分
        if (Objects.nonNull(customerPointBO)) {
            Long currentPoint = customerPointBO.getCurrentPoint();
            if (Objects.nonNull(currentPoint)) {
                accountBO.setBonusPoint(currentPoint + "");
            }

        }

        // 优惠券数量
        if (Objects.nonNull(couponNumBO)) {
            Integer count = couponNumBO.getCount();
            if (Objects.nonNull(count)) {
                accountBO.setCoupon(Long.parseLong(count + ""));
            }

        }

        return accountBO;
    }

    private void checkPrivateSphere(PrivateSphere privateSphere) {
        if (Objects.isNull(privateSphere)) {
            throw new BizException("私域信息不能为空");
        }

        if (StringUtils.isEmpty(privateSphere.getCorpId())) {
            throw new BizException("corpId不能为空");
        }

        if (Objects.isNull(privateSphere.getBosId())) {
            throw new BizException("bosId不能为空");
        }
    }

    /**
     * 检查手动触发同步历史外部联系人
     *
     * @param request
     * @return
     */
    public SyncHistoryExternaluserBO checkSyncHistoryCustomer(BaseRequest request) {
        SyncHistoryExternaluserBO syncHistoryExternaluserBO = new SyncHistoryExternaluserBO();
        //获取corpid
        PrivateSphere privateSphere = privateSphereThird.fetch(request.getBasicInfo(), true);
        // 手动同步
        syncHistoryExternaluserBO.setSyncFlag(redisService.exist(RedisKeyConstant.getManualSyncExternaluserKey(String.valueOf(privateSphere.getBosId()))));
        if (syncHistoryExternaluserBO.getSyncFlag()) {
            syncHistoryExternaluserBO.setLatestSyncTime((Long) redisService.get(RedisKeyConstant.getManualSyncExternaluserKey(String.valueOf(privateSphere.getBosId()))));
        }
        syncHistoryExternaluserBO.setDefaultSyncTime(manualSyncDefaultTime);

        // 自动同步
        syncHistoryExternaluserBO.setAutoSyncFlag(redisService.exist(RedisKeyConstant.getAutoSyncExternaluserKey(String.valueOf(privateSphere.getBosId()))));
        if (syncHistoryExternaluserBO.getAutoSyncFlag()) {
            syncHistoryExternaluserBO.setLatestAutoSyncTime((Long) redisService.get(RedisKeyConstant.getAutoSyncExternaluserKey(String.valueOf(privateSphere.getBosId()))));
        }
        syncHistoryExternaluserBO.setDefaultAutoSyncTime(autoSyncDefaultTime);

        return syncHistoryExternaluserBO;
    }

    /**
     * 手动触发同步历史外部联系人
     *
     * @param request
     * @return
     */
    public Boolean syncHistoryCustomer(BaseRequest request) {
        //0.根据basicInfo，换取私域
        PrivateSphere privateSphere = privateSphereThird.fetch(request.getBasicInfo(), true);

        SyncCustomerTriggerDTO syncCustomerTriggerDTO = new SyncCustomerTriggerDTO();
        syncCustomerTriggerDTO.setCorpId(privateSphere.getCorpId());
        syncCustomerTriggerDTO.setBosId(privateSphere.getBosId());
        syncCustomerTriggerDTO.setManualFlag(true);

        Boolean flag = redisService.setNX(RedisKeyConstant.getManualSyncExternaluserKey(String.valueOf(privateSphere.getBosId())), String.valueOf(System.currentTimeMillis()), manualSyncDefaultTime, TimeUnit.MINUTES);
        if (flag) {
            log.info("手动触发历史外部联系人同步 triggerSyncCustomer request:{}", JSON.toJSONString(syncCustomerTriggerDTO));
            this.triggerSyncCustomer(syncCustomerTriggerDTO);
            log.info("手动触发历史外部联系人同步 triggerSyncCustomer response:{}", JSON.toJSONString(flag));
        }

        return flag;
    }

    public Boolean sendCustomerSearchMsg(CustomerSearchMsgDTO customerSearchMsgDTO) {
        return sendCustomerUpdateMsg(customerSearchMsgDTO);
    }



    private Boolean sendCustomerUpdateMsg(CustomerSearchMsgDTO customerSearchMsgDTO) {
        BasicInfo basicInfo = customerSearchMsgDTO.getBasicInfo();

        CustomerChangeEventMsg customerChangeEventMsg = new CustomerChangeEventMsg();
        customerChangeEventMsg.setBosId(basicInfo.getBosId());
        customerChangeEventMsg.setSourceProductInstanceId(basicInfo.getProductInstanceId());
        customerChangeEventMsg.setSourceProductId(basicInfo.getProductId());
        customerChangeEventMsg.setWids(Lists.newArrayList(customerSearchMsgDTO.getWid()));

        ArtemisBaseInfo<CustomerChangeEventMsg> artemisBaseInfo = new ArtemisBaseInfo<>();
        artemisBaseInfo.setTopic(ArtemisConstant.Topic.CORE_EXTERNALUSER_CHANG_EVENT);
        artemisBaseInfo.setEvent(customerChangeEventMsg);
        artemisBaseInfo.setProducer(ArtemisConstant.USER);

        log.info("通知客搜客户变更, bosId:{}, wid:{}", basicInfo.getBosId(), customerSearchMsgDTO.getWid());
        return artemisService.sendToArtemis(artemisBaseInfo, basicInfo.getBosId());
    }


    public Boolean mergeCustomerWid(List<CustomerWidMergeDTO> dtoList) {
        log.info("客户服务接受wid合并消息,param:{}",JSON.toJSON(dtoList));
        //1、判断被合并的wid是不是企微渠道wid，如果不是，不用走合并流程
        Map<Long, Map<Long, Long>> groupMap = new HashMap<>();
        for (CustomerWidMergeDTO customerWidMergeDTO : dtoList) {
            Map<Long, Long> customerWidMergeDTOS = groupMap.get(customerWidMergeDTO.getBosId());
            if (customerWidMergeDTOS == null) {
                customerWidMergeDTOS = new HashMap<>();
                customerWidMergeDTOS.put(customerWidMergeDTO.getOldWid(), customerWidMergeDTO.getNewWid());
                groupMap.put(customerWidMergeDTO.getBosId(), customerWidMergeDTOS);
            } else {
                customerWidMergeDTOS.put(customerWidMergeDTO.getOldWid(), customerWidMergeDTO.getNewWid());
            }
        }
        groupMap.forEach((k, v) -> {
            PrivateSphere privateSphereRequest = new PrivateSphere();
            privateSphereRequest.setBosId(k);
            privateSphereRequest.setProductId(aewcProductId);
            SoaResponse<PrivateSphere, Void> privateSphereResultResponse =
                    privateSphereService.fetch(privateSphereRequest);
            PrivateSphere privateSphereResponse = privateSphereResultResponse.getResponseVo();
            if (privateSphereResponse == null) {
                //不是企微的客户或者解绑先不处理（解绑客搜会删除，绑定后重刷一遍）
                return;
            }
            List<UCInfoDetailResult> ucInfoDetailResultList =
                    remoteOutServiceProxy.findUserInfoByWids(privateSphereResponse.getBosId(), null,
                            null, privateSphereResponse.getCorpId(), Lists.newArrayList(v.keySet()));
            //ucInfoDetailResultList 这里是要做合并的
            if (CollectionUtils.isEmpty(ucInfoDetailResultList)) {
                return;
            }
            //开始查询本地数据推送到客户搜索平台
            for (UCInfoDetailResult ucInfoDetailResult : ucInfoDetailResultList) {
                Long newWid = v.get(ucInfoDetailResult.getWid());
                if (newWid == null) {
                    //判空，理论不会出现
                    log.error("mergeCustomerWid newWid mapping error:{}", JSON.toJSONString(ucInfoDetailResult));
                    continue;
                }

                Customer customerResult = customerServiceProxy.fetchCustomer(null, ucInfoDetailResult.getOpenId(), privateSphereResponse, ExternalUserTypeEnum.WECHAT_CUSTOMER);

                if (customerResult == null) {
                    continue;
                }
                //获取客户员工关系
                List<CustomerEmployeeRelation> dataList;
                try {
                    //只需要ID就可以又查了一遍员工详情，后续优化
                    dataList = customerServiceProxy.fetchCustomerEmployeeRelation(customerResult.getId(), null, privateSphereResponse, null, null, false);
                } catch (Exception e) {
                    log.error("查询客户员工关系错误,e", e);
                    continue;
                }

                Integer gender = null;
                if (customerResult.getGender() != null) {
                    gender = customerResult.getGender().getCode();
                }
                //重推一遍客户搜索
                log.info("wid 合并后重推客户搜索,oldWid{}.newWid:{},private:{}",
                        ucInfoDetailResult.getWid(), newWid, JSON.toJSONString(privateSphereResponse));

                List<String> phoneList = new ArrayList<>();
                if (StringUtils.isNotBlank(customerResult.getMobiles())) {
                    phoneList.add(customerResult.getMobiles());
                } else {
                    if (StringUtils.isNotBlank(customerResult.getPhone())) {
                        phoneList.add(customerResult.getPhone());
                    }
                }

                addCorpExternaluserSecondHandler.initCustomerSearchMsg(customerResult, newWid,
                        dataList, privateSphereResponse, phoneList);
            }

        });
        return true;
    }

    /**
     * 检索查询外部联系人
     *
     * @param externalUserInfoFindDTO
     * @return
     */
    public PageResponse<ExternalUserListBO> getExternalUserBySearch(ExternalUserInfoFindDTO externalUserInfoFindDTO) {


        //1、获取corpId（查询都依赖corpID)
        PrivateSphere privateSphere = privateSphereThird.fetch(externalUserInfoFindDTO.getBasicInfo(), true);

        //2、根据入参条件进行搜索
        BaseAuthReqDTO<CustomerSearchDTO> baseAuthReqDTO = new BaseAuthReqDTO<>();
        List<ExternalUserListBO> resultList = Lists.newArrayList();


        CustomerSearchBO customerSearchBO;
        do {
            externalUserInfoFindDTO.setPageNum(externalUserInfoFindDTO.getPageNum());
            externalUserInfoFindDTO.setPageSize(externalUserInfoFindDTO.getPageSize());
            CustomerSearchDTO customerSearchDTO = CustomerRequestBuild.buildOneCrmSearchRequest(privateSphere.getCorpId(), externalUserInfoFindDTO);
            baseAuthReqDTO.setRequest(customerSearchDTO);
            //客户搜索
            log.info("queryExternalUserBaseInfoList, param:{}, ticket:{}", JSON.toJSONString(externalUserInfoFindDTO), ZipkinContext.getContext().getGlobalTicket());
            customerSearchBO = SoaUtil.unpack(oneCrmAdapterService.searchUserInfoByPage(baseAuthReqDTO));


            List<ExternalUserListBO> externalUserListBOS = new ArrayList<>();
            if (CollectionUtils.isNotEmpty(customerSearchBO.getExternalUserList())) {

                for (ExternalUserBO externalUserBO : customerSearchBO.getExternalUserList()) {
                    ExternalUserListBO externalUserListBO = new ExternalUserListBO();
                    externalUserListBO.setExternalUserId(externalUserBO.getExternalUserId());
                    externalUserListBO.setExternalUserWid(externalUserBO.getWid());
                    externalUserListBOS.add(externalUserListBO);
                }
            }

            resultList.addAll(externalUserListBOS);

            if (externalUserInfoFindDTO.getSearchAllUser() != null && externalUserInfoFindDTO.getSearchAllUser()) {
                //查询所有用户
                externalUserInfoFindDTO.setPageNum(externalUserInfoFindDTO.getPageNum() + 1);
            }
            //上游传查询所有用户标识是查所有用户 并且 可以一直查到wid 则一直循环
        } while (externalUserInfoFindDTO.getSearchAllUser() != null && externalUserInfoFindDTO.getSearchAllUser()
                && customerSearchBO.getExternalUserList() != null && externalUserInfoFindDTO.getPageSize().equals(customerSearchBO.getExternalUserList().size()));


        PageResponse<ExternalUserListBO> response = new PageResponse<>();
        response.setResults(resultList);
        response.setTotalCount(customerSearchBO.getTotalCount());
        return response;
    }

    public List<CustomerAddWayBO> getCustomerAddWayEnum(BaseRequest request) {
        List<CustomerAddWayBO> customerAddWayBOS = new ArrayList<>();

        for (ExternalUserAddWayEnum addWayEnum : ExternalUserAddWayEnum.values()) {
            CustomerAddWayBO customerAddWayBO = new CustomerAddWayBO();
            customerAddWayBO.setCode(addWayEnum.getCode());
            customerAddWayBO.setValue(addWayEnum.getDesc());
            customerAddWayBOS.add(customerAddWayBO);
        }

        return customerAddWayBOS;
    }


    public PageResponse<CustomerCouponsBO> getCustomerCoupons(CustomerCouponsDTO couponsDTO) {
        //0.根据basicInfo，换取私域
        PrivateSphere privateSphere = privateSphereThird.fetch(couponsDTO.getBasicInfo(), true);

        if (StringUtils.isEmpty(couponsDTO.getExternalUserId()) && StringUtils.isEmpty(couponsDTO.getCustomerId())) {
            throw new SoaException(BaseErrorCode.PARMA_EXCPETION.getCode().toString(), BaseErrorCode.PARMA_EXCPETION.getMsg());
        }

        Customer customer = customerServiceProxy.fetchCustomer(couponsDTO.getCustomerId(), couponsDTO.getExternalUserId(), privateSphere, ExternalUserTypeEnum.ALL);
        // 获取客户基本信息
        if (customer == null) {
            return new PageResponse(Lists.newArrayList(), couponsDTO.getPageNum(), couponsDTO.getPageSize(), 0L);
        }

        // 获取wid
        Long customerWid = customerThird.getSuperWid(privateSphere.getBosId(), customer.getExternalUserid(), privateSphere.getCorpId());
        if (customerWid == null) {
            return new PageResponse(Lists.newArrayList(), couponsDTO.getPageNum(), couponsDTO.getPageSize(), 0L);
        }

        CustomerCouponsAdapterRequest request = new CustomerCouponsAdapterRequest();
        request.setBosId(couponsDTO.getBasicInfo().getBosId());
        request.setProductInstanceId(couponsDTO.getBasicInfo().getProductInstanceId());
        request.setVid(couponsDTO.getBasicInfo().getVid());
        request.setTcode(privateSphere.getTcode());
        request.setPageNum(couponsDTO.getPageNum());
        request.setWid(customerWid);
        request.setPageSize(couponsDTO.getPageSize());
        // 1 未使用 2已使用 3已过期
        request.setStatusRange(Lists.newArrayList(1));

        CustomerCouponSPIDTO customerCoupon = SoaUtil.unpack(crmAdapterService.getCustomerCoupon(request));
        List<CustomerCouponsBO> customerCouponsBOS = new ArrayList<>();
        Long totalCount = 0L;
        if (customerCoupon != null && CollectionUtils.isNotEmpty(customerCoupon.getPageList())) {
            for (CustomerCouponSPIDTO.PageListBean item : customerCoupon.getPageList()) {
                CustomerCouponsBO customerCouponsBO = new CustomerCouponsBO();
                customerCouponsBO.setCouponTitle(item.getName());
                customerCouponsBO.setDetail(item.getExplain());
                customerCouponsBO.setType(item.getCouponType());
                customerCouponsBO.setFreightReduceType(item.getFreightReduceType());
                // 0 无门槛减免金额 1 固定减免 2 每满多少减多少
                customerCouponsBO.setSubCouponType(item.getReducePriceType());
                if (CouponTypeEnum.DISCOUNT_COUPON.getCode().equals(item.getCouponType())) {
                    customerCouponsBO.setDiscount(item.getDiscountAmount());
                }
                if (CouponTypeEnum.VOUCHER.getCode().equals(item.getCouponType()) || CouponTypeEnum.FREIGHT_COUPON.getCode().equals(item.getCouponType())) {
                    customerCouponsBO.setCashTicketAmt(item.getDiscountAmount());
                }

                customerCouponsBO.setCashTicketCondition(item.getUseThreshold());
                if (item.getValidDate() != null && item.getValidDate().getUseEndTime() != null) {
                    try {
                        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                        Date parse = simpleDateFormat.parse(item.getValidDate().getUseEndTime());
                        customerCouponsBO.setExpDate(parse.getTime());
                    } catch (Exception e) {
                        log.info("时间转换失败");
                    }

                }
                customerCouponsBOS.add(customerCouponsBO);
            }
            totalCount = customerCoupon.getTotalCount();
        }
        return new PageResponse(customerCouponsBOS, couponsDTO.getPageNum(), couponsDTO.getPageSize(), totalCount);
    }

    public List<ExternalUserListBO> getCustomerByWids(ExternalUserInfoByWidsDTO externalUserInfoByWidsDTO) {
        List<ExternalUserListBO> externalUserListBOS = Lists.newArrayList();
        if (externalUserInfoByWidsDTO.getBasicInfo() == null || CollectionUtils.isEmpty(externalUserInfoByWidsDTO.getWids())) {
            return externalUserListBOS;
        }
        //跟进basicInfo换取私域
        PrivateSphere privateSphere = privateSphereThird.fetch(externalUserInfoByWidsDTO.getBasicInfo(), true);

        for (Long wid : externalUserInfoByWidsDTO.getWids()) {
            UCInfoFindDTO ucInfoFindDTO = new UCInfoFindDTO();
            ucInfoFindDTO.setBosId(externalUserInfoByWidsDTO.getBasicInfo().getBosId());
            ucInfoFindDTO.setPiid(externalUserInfoByWidsDTO.getBasicInfo().getProductInstanceId());
            ucInfoFindDTO.setWidList(Lists.newArrayList(wid));
            ucInfoFindDTO.setSourceType(UCSourceTypeEnum.WORK_WEIXIN_EXTERNAL_USERID);
            UCInfoFindBO ucInfoFindBO = SoaUtil.unpack(oneCrmAdapterService.findUserInfoByWids(ucInfoFindDTO));
            final List<UCInfoDetailResult> ucInfoDetailResultList = ucInfoFindBO.getUcInfoDetailResultList();
            if (ucInfoDetailResultList == null || ucInfoDetailResultList.size() == 0) {
                continue;
            }


            UCInfoDetailResult ucInfoDetailResult = null;
            if (ucInfoDetailResultList.size() == 1) {
                ucInfoDetailResult = ucInfoDetailResultList.get(0);
            } else {
                //出现了wid合并情况,多个appid 需要查询私域信息(场景较少）
                log.info("customerSearchCallback,wid合并场景, wid:{}", wid);

                for (UCInfoDetailResult infoDetailResult : ucInfoDetailResultList) {
                    if (infoDetailResult.getAppId().equals(privateSphere.getCorpId())) {
                        //找到当前绑定的corpId
                        ucInfoDetailResult = infoDetailResult;
                        break;
                    }
                }
                if (ucInfoDetailResult == null) {
                    //默认取第一个 理论上不会发生（对结果不会有错误情况，但是可能少数据，后续需要补数据）
                    log.warn("customerSearchCallback,回调找不到对应corpId, wid:{}", wid);
                    ucInfoDetailResult = ucInfoDetailResultList.get(0);
                }

            }

            ExternalUserListBO externalUserListBO = new ExternalUserListBO();
            externalUserListBO.setCorpId(privateSphere.getCorpId());
            externalUserListBO.setExternalUserId(ucInfoDetailResult.getOpenId());
            externalUserListBO.setExternalUserWid(wid);
            externalUserListBOS.add(externalUserListBO);
        }
        return externalUserListBOS;
    }

    private Map<String, List<CustomerStageBO>> queryStageInfoByCustomer(Set<String> customerIdSet, PrivateSphere privateSphere) {
        //1.valid
        if (CollectionUtils.isEmpty(customerIdSet)) {
            return Collections.emptyMap();
        }
        Assert.notNull(privateSphere.getPrivateSphereId(), "私域id不能我空");
        //2.查询
        SingleRequest<HashSet<String>> request = new SingleRequest(customerIdSet);
        request.setPrivateSphere(privateSphere);
        Map<String, List<CustomerStageRelation>> map = SoaUtil.unpack(stageRelationService.fetchRelationByCustomers(request));
        if (map.isEmpty()) {
            return new HashMap<>();
        }
        Map<String, List<CustomerStageBO>> result = new HashMap<>();
        map.forEach((k, v) -> {
            List<CustomerStageBO> itemList = new ArrayList<>();
            for (CustomerStageRelation relation : v) {
                CustomerStageBO customerStageBO = new CustomerStageBO();
                CustomerStage customerStage = relation.getCustomerStage();
                if (Objects.nonNull(customerStage)) {
                    customerStageBO.setStageId(customerStage.getStageId());
                    customerStageBO.setStageName(customerStage.getStageName());
                }
                CustomerProcess customerProcess = relation.getCustomerProcess();
                if (Objects.nonNull(customerProcess)) {
                    customerStageBO.setProcessId(customerProcess.getProcessId());
                    customerStageBO.setProcessName(customerProcess.getProcessName());
                }
                itemList.add(customerStageBO);
            }
            result.put(k, itemList);
        });
        return result;
    }

    public Boolean checkIsFriended(CustomerDetailDTO customerDetailDTO) {
        //1.valid
        String customerId = customerDetailDTO.getCustomerId();
        String userId = customerDetailDTO.getUserId();
        Assert.notNull(userId, "userId不能为空");
        Assert.notNull(customerId, "customerId不能为空");
        //2.获取私域
        PrivateSphere privateSphere = privateSphereThird.fetch(customerDetailDTO.getBasicInfo(), Boolean.TRUE);

        //3.获取员工数据
        Employee employee = customerThird.queryEmployee(privateSphere, null, userId);
        if (Objects.isNull(employee) || StringUtils.isBlank(employee.getId())) {
            throw new BizException("未找到对应的员工信息");
        }
        EmployeeStatusEnum status = employee.getStatus();
        EmployeeActiveStatusEnum activeStatus = employee.getActiveStatus();
        if (EmployeeActiveStatusEnum.INACTIVE.equals(activeStatus) || EmployeeStatusEnum.USER_UN_AUTHORIZATION.equals(status)) {
            throw new BizException("当前员工无坐席或者不在授权范围内");
        }
        CustomerEmployeeRelation relation;
        try {
            List<CustomerEmployeeRelation> relationList = customerServiceProxy.fetchCustomerEmployeeRelation(customerId, employee.getId(), privateSphere, null, null, null);

            if (CollectionUtils.isEmpty(relationList)) {
                throw new BizException("该客户已不是好友");
            }

            relation = relationList.get(0);
        } catch (Exception e) {
            throw new BizException("该客户已不是好友");
        }

        if (CustomerStatusEnum.UNAUTHORIZED.equals(relation.getStatus())) {
            throw new BizException("当前员工无坐席或者不在授权范围内");
        }

        if (Boolean.FALSE.equals(relation.getFriended())) {
            throw new BizException("该客户已不是好友");
        }

        return Boolean.TRUE;
    }

    public CustomerBaseInfoApi queryCustomerBaseInfoForApi(CustomerQueryApi queryDTO) {
        BasicInfo basicInfo = queryDTO.convertToBasicInfo();
        //1.获取私域
        PrivateSphere privateSphere = privateSphereThird.fetch(basicInfo, Boolean.TRUE);
        //2.获取客户信息
        String externalUserId = queryDTO.getExternalUserId();
        Long wid = queryDTO.getWid();
        if (Objects.isNull(externalUserId) && Objects.isNull(wid)) {
            throw new BizException("externalUserId和wid不能同时为空");
        }
        //3.通过wid换取externalUserId
        if (Objects.isNull(externalUserId)) {
            //换取externalUserId
            List<PassPortAccountMappingRes> accountMappingResList = remoteOutServiceProxy.getPassportAccountMappingRes(privateSphere, Collections.singletonList(wid));
            if (CollectionUtils.isEmpty(accountMappingResList) || Objects.isNull(accountMappingResList.get(0))) {
                throw new BizException("未查询到当前wid对应的externalUserId");
            }
            PassPortAccountMappingRes accountMappingRes = accountMappingResList.get(0);
            externalUserId = accountMappingRes.getExternalUserId();
        }
        //4.查询客户信息
        CustomerIdGetDTO customerIdGetDTO = new CustomerIdGetDTO();
        customerIdGetDTO.setExternalUserId(externalUserId);
        CustomerDetailBO customerBaseInfo = getCustomerBaseInfo(customerIdGetDTO, privateSphere);
        if(Objects.isNull(customerBaseInfo)){
            throw new BizException("未查询到客户信息");
        }
        //5.结果转换
        CustomerBaseInfoApi customerBaseInfoApi = new CustomerBaseInfoApi();
        customerBaseInfoApi.setCustomerId(customerBaseInfo.getCustomerId());
        customerBaseInfoApi.setExternalUserId(customerBaseInfo.getExternalUserId());
        customerBaseInfoApi.setFirstAddTime(customerBaseInfo.getFirstAddTime());
        customerBaseInfoApi.setExternalUserType(customerBaseInfo.getExternalUserType());
        customerBaseInfoApi.setNickName(customerBaseInfo.getNickName());
        customerBaseInfoApi.setAvatar(customerBaseInfo.getAvatar());
        customerBaseInfoApi.setGender(customerBaseInfo.getGender());
        customerBaseInfoApi.setStatus(customerBaseInfo.getStatus());
        return customerBaseInfoApi;
    }
}
